2012-04-15 11 views
54

Attualmente sto memorizzando lo stato utilizzando i dati jQuery per l'elemento dom.Qual è il modo preferito per memorizzare lo stato tra init e update per il binding knockout personalizzato?

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         
     } 
    } 

};​ 

C'è un posto migliore per memorizzare lo stato per associazione che non richiede il dom? È possibile utilizzare il bindingContext per memorizzare lo stato per ciascuna istanza dell'associazione?

+0

Buona domanda. Immagino che la tua soluzione sia molto buona. Ulteriori miglioramenti potrebbero essere fatti considerando alcune altre specifiche del tuo codice. – Oybek

+1

Secondo. Ogni associazione è correlata a uno specifico dom node, pertanto la memorizzazione dei relativi dati associati a quel nodo dom è una buona strada da percorrere. – Niko

risposta

46

Il bindingContext è una possibilità, ma solo per il passaggio di dati da init a update la prima volta che viene attivata l'associazione. La prossima volta che update si spegne non ci sarà più.

Ci sono due scelte per dove memorizzare questo tipo di Stato:

1- Sul elemento, come avete dichiarato. È possibile utilizzare jQuery $.data o KO include API per fare anche questo ko.utils.domData.get(element, key) e ko.utils.domData.set(element, key, value).

2- Inserire questo tipo di informazioni nel modello di vista, se appropriato. Un flag per indicare isEditing non è necessariamente fuori luogo in un modello di vista. Personalmente, come a mettere questo tipo di "meta-dati", come sub-osservabili fuori di un simile osservabile:

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

si sarebbe in grado di legare contro name e name.isEditing.

Questo ha alcuni vantaggi:

  • mantiene il modello di visione abbastanza pulita, come non si stanno introducendo nuove proprietà di alto livello
  • mantiene il sub-osservabile legato al suo genitore osservabile (senza bisogno di nameIsEditing , ecc.)
  • quando convertito in JSON con qualcosa come ko.toJSON il sotto-osservabile isEditing verrà semplicemente eliminato quando il relativo genitore viene scartato. Quindi, non invierai i valori non necessari al server.
  • in questo caso, può anche avere il vantaggio di essere disponibile per altri calcoli nel modello di visualizzazione o per eseguire il binding di più elementi nell'interfaccia utente.
+0

Mi manca qualcosa ma se dichiari che l'isEditing è osservabile e quindi hai controllato il valore di questo osservabile nella funzione di aggiornamento del bind, creerai un oggetto attendibile e poi quando cambierai il valore di isEditing in true nel la funzione init appena prima di modificare il valore dell'osservabile limitato, isEditing attiverà una modifica che costringerà a chiamare la funzione di aggiornamento del binding personalizzato. Se dichiaro isEditing come una semplice variabile JS, la tua soluzione funziona perfettamente. – Samuel

+0

perché domData è migliore di $ .data? perché fa parte del ko o per qualche altro motivo? –

7

Il collegamento dei dati all'elemento va bene e Knockout utilizza questo metodo internamente per i collegamenti del flusso di controllo (se, con, ecc.), Ad esempio.

Un altro metodo è utilizzare la funzione init e utilizzare un osservabile calcolato per gestire gli aggiornamenti. Io uso questo metodo nel mio binding repeat. Qui ci sono le parti importanti:

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

Io uso spesso questo schema:

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

Mi rendo conto che questa domanda è vecchio, ma mi sono imbattuto qui in cerca di un approccio così ho pensato di chip su un altro metodo moderno ko.

Si potrebbe semplicemente aggiungere proprietà al bindingContext. $ Dati direttamente. Ho scelto un nome variabile fastidioso, "___IsEditing", per evitare potenziali collisioni, ma ti viene l'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

utilizzo una funzione di creare un ambito comune per init e aggiornamento, definendo i dati comuni all'interno della funzione.

Problemi correlati