2012-04-15 7 views
54

Actualmente estoy almacenando el estado usando datos jQuery para el elemento dom.¿Cuál es la forma preferida de almacenar el estado entre el inicio y la actualización para el enlace personalizado knockout?

ko.bindingHandlers.customValue = { 

    init: function init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     var state = { isEditing: false };   
     $(element).focus(function focus() { 
      state.isEditing = true; 
     }).blur(function blur() { 
      state.isEditing = false;    
     }).data("customBinding", state); 

    }, 

    update: function update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     // ignore if updating 
     if (!$(element).data("customBinding").isEditing) { 
      // handle update if they are not updating         
     } 
    } 

};​ 

¿Hay un lugar mejor para almacenar el estado por enlace que no requiere la dom? ¿Se puede usar el bindingContext para almacenar el estado de cada instancia del enlace?

+0

Buena pregunta. Supongo que tu solución es muy buena. Se pueden hacer mejoras adicionales teniendo en cuenta algunos otros detalles de su código. – Oybek

+1

Yo en segundo lugar. Cada enlace está relacionado con un nodo dom específico, por lo tanto, almacenar datos relacionados vinculados a ese nodo dom es una buena forma de hacerlo. – Niko

Respuesta

46

La bindingContext es una posibilidad, pero solo para pasar datos de init a update la primera vez que se activa la vinculación. La próxima vez que se dispare update, ya no estará allí.

En realidad, hay dos opciones para dónde almacenar este tipo de Estado:

1- En el elemento, como ha afirmado. Puede usar jQuery's $.data o KO incluye API para hacer esto también ko.utils.domData.get(element, key) y ko.utils.domData.set(element, key, value).

2- Coloque este tipo de información en su modelo de vista, si corresponde. Una bandera para indicar isEditing no está necesariamente fuera de lugar en un modelo de vista. Personalmente, me gusta poner este tipo de "metadatos" como sub-observables fuera de un observables como:

var name = ko.observable("Bob"); 
name.isEditing = ko.observable(false); 

que sería capaz de unirse contra name y name.isEditing.

Esto tiene algunas ventajas:

  • mantiene el modelo de vista bastante limpio, ya que no se está introduciendo nuevas propiedades de nivel superior
  • mantiene la sub-observables atado a su matriz observables (sin necesidad de nameIsEditing , etc.)
  • cuando se convierte en JSON con algo como ko.toJSON, el sub-observable isEditing simplemente se eliminará cuando se desenrolla el elemento primario. Por lo tanto, no enviará valores innecesarios al servidor.
  • En este caso, también puede tener la ventaja de estar disponible para otros cálculos en su modelo de vista o vincularse contra varios elementos en su UI.
+0

Me falta algo, pero si declara que isEditing es observable y luego ha comprobado el valor de este observable en la función de actualización de la vinculación, creará un dependdable dependiente y luego, cuando cambie el valor de isEditing a true en el La función init justo antes de cambiar el valor del observable delimitado, isEditing activará un cambio que obligará a llamar a la función de actualización del enlace personalizado. Si declaro que está editando como una simple variable JS, su solución funciona perfectamente. – Samuel

+0

¿por qué domData es mejor que $ .data? porque es parte de ko o por alguna otra razón? –

7

La conexión de datos al elemento está bien, y Knockout usa este método internamente para las uniones de flujo de control (si, con, etc.), por ejemplo.

Otro método es usar solo la función init y usar un elemento observable calculado para manejar las actualizaciones. Utilizo este método en mi enlace repeat. Estas son las partes importantes:

ko.bindingHandlers['repeat'] = { 
    'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
     ... 
     // set up persistent data 
     var lastRepeatCount = 0; 
     ... 
     ko.computed(function() { 
      var repeatCount = ko.utils.unwrapObservable(valueAccessor()); 
      ... 
      // Remove nodes from end if array is shorter 
      for (; lastRepeatCount > repeatCount; lastRepeatCount--) { 
       ... 
      } 
      ... 
      // Add nodes to end if array is longer (also initially populates nodes) 
      for (; lastRepeatCount < repeatCount; lastRepeatCount++) { 
       ... 
      } 
     }, null, {'disposeWhenNodeIsRemoved': placeholder}); 
     ... 
    } 
}; 
1

que a menudo utilizan este patrón:

define(['knockout'], function(ko) { 
    var interInstanceVariable = null; 

    function Tree(element) { 
    var privateInstanceVariable = null; 

    function privateInstanceMethod() {} 

    this.publicInstanceMethod = function() {} 
    } 


    ko.bindingHandlers.cannDendrogram = { 
    init: function(element, valueAccessor) { 
     $(element).data('tree', new Tree(element)); 
    }, 
    update: function(element, valueAccessor) { 
     var tree = $(element).data('tree'); 
     tree.publicMethod(); 
    } 
    }; 
}); 
1

realizo esta pregunta es viejo, pero me encontré aquí buscando el enfoque por lo pensé chip en una mayor método moderno ko.

Simplemente puede agregar propiedades al bindingContext. $ Data directamente. Elegí un nombre de variable molesto, "___IsEditing", para evitar posibles colisiones, pero se entiende la idea ...

ko.bindingHandlers.customValue = { 

init: function init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
    bindingContext.$data.___IsEditing = false;   
    $(element).focus(function focus() { 
     bindingContext.$data.___IsEditing = true; 
    }).blur(function blur() { 
     bindingContext.$data.___IsEditing = false;    
    }).data("customBinding", state); 

}, 

update: function update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
    // ignore if updating 
    if (bindingContext.$data.___IsEditing) { 
     // handle update if they are not updating         
    } 
} 

};

-2

I utilizar una función para crear un alcance común para init y actualizar, mediante la definición de los datos comunes dentro de la función.

Cuestiones relacionadas