2011-08-05 12 views
5

Estoy tratando de agregar JS knockout a una página de búsqueda en nuestro sitio web. Actualmente, abre un cuadro de diálogo jQuery, que tiene varias casillas de verificación de criterios que puede seleccionar.¿Cómo crear una matriz observable con deshacer?

Hay varios cuadros de diálogo con múltiples tipos de criterios. Cuando abre el cuadro de diálogo, las casillas de verificación no entran en vigencia hasta que presiona el botón "Actualizar", si hace clic en cancelar o simplemente cierra la ventana, los cambios realizados se revierten y el cuadro de diálogo se establece en su estado anterior.

He leído this y algunas otras publicaciones. Sin embargo, esto parece funcionar solo con ko.observable, y parece que no puedo hacer que funcione con ko.observableArray.

¿Alguien ha logrado esto o tiene alguna idea?

Un ejemplo de lo que quiero hacer:

HTML:

<form> 
    <div> 
     <div> 
      <label><input type="checkbox" data-bind="checked: genders" value="1" />Male</label> 
      <label><input type="checkbox" data-bind="checked: genders" value="2" />Female</label> 
     </div> 
    </div> 
    <a id="buttonCancel">Cancel</a> 
    <a id="buttonUpdate">Update</a> 
</form> 
<div data-bind="text: ko.toJSON(viewModel)"></div> 

Javascript:

var viewModel = { 
    genders: ko.observableArrayWithUndo([]) 
}; 

ko.applyBindings(viewModel); 

$('#buttonCancel').click(function(){ 
    viewModel.genders.resetChange(); 
}); 

$('#buttonUpdate').click(function(){ 
    viewModel.genders.commit(); 
    return false; 
}); 

Respuesta

6

Aquí habría una manera de acercarse a ella:

//wrapper to an observableArray of primitive types that has commit/reset 
ko.observableArrayWithUndo = function(initialArray) { 
    var _tempValue = ko.observableArray(initialArray.slice(0)), 
     result = ko.observableArray(initialArray); 

    //expose temp value for binding 
    result.temp = _tempValue; 

    //commit temp value 
    result.commit = function() { 
     result(_tempValue.slice(0)); 
    }; 

    //reset temp value 
    result.reset = function() { 
     _tempValue(result.slice(0)); 
    }; 

    return result; 
}; 

Tu vincularías tu casillas de verificación a su Nombre.temp y la otra parte de su UI a solo su Nombre.

Este es un ejemplo: http://jsfiddle.net/rniemeyer/YrfyW/

La rebanada (0) es una forma de obtener una copia superficial de una matriz (o incluso sólo slice()). De lo contrario, estaría realizando operaciones en una referencia a la misma matriz.

+0

¡Gracias por la respuesta rápida! Déjame ver cómo funciona. –

3

Dada HTML similar a:

<div> 
    <button data-bind="click: function() { undo(); }">Undo</button> 
    <input data-bind="value: firstName" /> 
    <input data-bind="value: lastName" /> 
    <textarea data-bind="value: text"></textarea> 
</div> 

Se podría utilizar un código similar a este golpe de gracia, básicamente ahorro de la pila de deshacer como una representación de cadena JSON del estado después de cada cambio. Básicamente, usted crea un observable dependiente falso para suscribirse a todas las propiedades en la vista, alternativamente puede iterar y suscribirse manualmente a cada propiedad.

//current state would probably come from the server, hard coded here for example 
var currentState = JSON.stringify({ 
    firstName: 'Paul', 
    lastName: 'Tyng', 
    text: 'Text' 
}) 
    , undoStack = [] //this represents all the previous states of the data in JSON format 
    , performingUndo = false //flag indicating in the middle of an undo, to skip pushing to undoStack when resetting properties 
    , viewModel = ko.mapping.fromJSON(currentState); //enriching of state with observables 


//this creates a dependent observable subscribed to all observables 
//in the view (toJS is just a shorthand to traverse all the properties) 
//the dependent observable is then subscribed to for pushing state history 
ko.dependentObservable(function() { 
    ko.toJS(viewModel); //subscribe to all properties  
}, viewModel).subscribe(function() { 
    if(!performingUndo) { 
    undoStack.push(currentState); 
    currentState = ko.mapping.toJSON(viewModel); 
} 
}); 

//pops state history from undoStack, if its the first entry, just retrieve it 
    window.undo = function() { 
     performingUndo = true; 
     if(undoStack.length > 1) 
     { 
      currentState = undoStack.pop(); 
      ko.mapping.fromJSON(currentState, {}, viewModel); 
     } 
     else { 
      currentState = undoStack[0]; 
      ko.mapping.fromJSON(undoStack[0], {}, viewModel); 
     } 
     performingUndo = false; 
}; 

ko.applyBindings(viewModel); 

Tengo una muestra de N niveles de deshacer con nocaut aquí:

http://jsfiddle.net/paultyng/TmvCs/22/

Usted puede ser capaz de adaptarse a sus usos.

Cuestiones relacionadas