2012-05-14 8 views
12

Tengo una casilla de verificación vinculada a un observable en un modelo de vista. Tengo un requisito para, esencialmente, mostrar un "¿Estás seguro?" confirmación de confirmación si el usuario lo cambia de verdadero a falso. Me está costando tiempo calcular el mejor lugar para hacer que el cambio sea "cancelable". . .Knockout - ¿Cancelar un evento de cambio?

1) jQuery manejador del evento click 2) modelo de vista interno subscribe "beforeChange" 3) modelo de vista interno suscribirse (normal)

En cualquier caso, había mucho prefieren tener la oportunidad de cancelar el cambio directamente que reacciona al cambio, potencialmente revertiéndolo a su valor anterior si es necesario.

¿El evento de suscripción de Knockout le da la oportunidad de cancelar un cambio? Cualquier idea sería apreciada. ¡Gracias!

Respuesta

22

Aquí es una opción sencilla utilizando stopImmediatePropagation de jQuery:

http://jsfiddle.net/rniemeyer/cBvXM/

<input type="checkbox" data-bind="click: confirmCheck, checked: myvalue" /> 

JS:

var viewModel = { 
    myvalue: ko.observable(false), 
    confirmCheck: function(data, event) { 
     if (!confirm("Are you sure?")) { 
      event.stopImmediatePropagation();    
      return false; 
     } 
     return true; 
    } 
}; 
+0

Oh, Dios mío! Eso es fantásticamente útil. Nunca supe sobre stopImmediatePropagation() de jQuery. Aunque generalmente trato de evitar hacer referencia a cosas de jQuery fuera del núcleo de ViewModel, esta es una gran solución para mi problema. ¡Gracias de nuevo! – blaster

+2

En mi caso, 'event.stopImmediatePropagation' no detuvo el cambio del valor en ko viewModel. Tuve que volver a establecer el valor: 'var cb = event.target; ... data.myvalue (! cb.checked); ' – Sprockincat

+10

El orden del enlace de datos es * muy * importante en este caso. Si vincula el valor * antes * del evento, el enlace de valor se ejecuta primero. Si el evento está vinculado, se ejecutará primero y detendrá la propagación. Vea este violín para verlo roto: http://jsfiddle.net/8AuVj/ –

12

Debido a los problemas comentados en respuesta @RP Niemeyer, acabo implementado este extensor:

ko.extenders.confirmable = function(target, options) { 
    var message = options.message; 
    var unless = options.unless || function() { return false; } 
    //create a writeable computed observable to intercept writes to our observable 
    var result = ko.computed({ 
     read: target, //always return the original observables value 
     write: function(newValue) { 
      var current = target(); 

      //ask for confirmation unless you don't have 
      if (unless() || confirm(message)) { 
       target(newValue); 
      } else { 
       target.notifySubscribers(current); 
      } 
     } 
    }).extend({ notify: 'always' }); 

    //return the new computed observable 
    return result; 
}; 

A continuación, puede aplicar eso a su modelo como este:

var viewModel = { 
    myvalue: ko.observable(false).extend({confirmable: "Are you sure?"}); 
} 

Y, si hubo un caso en el que no se solicite confirmación (en este tonto ejemplo, nos saltaremos la confirmación durante marzo), usted puede hacer:

var viewModel = { 
    myvalue: ko.observable(false).extend({confirmable: { message: "Are you sure?", unless: function() { return new Date().getMonth() == 2 }} }); 
} 
+1

¡Magnífico! Se puede usar en muchos escenarios. Solo una cosa, debe usarse así: '.extend ({confirmable: {mensaje:" ¿Estás seguro? ", A menos que: function() {return new Date(). GetMonth() == 2}}}) ; ' – Sljux

+0

¡Agradable! Esa es una idea magníficamente diseñada. –

Cuestiones relacionadas