2011-11-26 17 views
33

quando inserisco nuovi elementi nel DOM dopo ko.applyBindings(); è stato chiamato, quindi knockout non riconoscerà questi nuovi elementi. Posso capire perché questo sta accadendo - non sono semplicemente indicizzati per knockout.knockout.js: aggiorna i collegamenti?

Quindi, all'inizio pensavo che questo sarebbe stato risolto semplicemente chiamando di nuovo ko.applyBindings(), dopo aver aggiunto i miei nuovi elementi, MA poi mi sono reso conto che per ogni ko.applyBindings() chiamata che fai, gli eventi secondo ottengono licenziato più volte. Quindi, dopo aver applicato cinque volte, un clic: il binding verrà licenziato cinque volte, quindi questa non è una soluzione desiderabile;)

C'è qualcosa come ko.updateBindings() o qualcos'altro, per dirlo a knockout, beh .. aggiorna i collegamenti degli elementi?

saluti, Chris

+1

Puoi pubblicare del codice per mostrare cosa stai facendo? –

+0

bene, ad esempio qualcosa di simile: $ ('body'). Append ('Click me!'); –

+0

Non sono sicuro che sia abbastanza contesto per fornire una risposta utile. Capisco cosa stai cercando di fare, ma con un'immagine più completa del tuo codice (perché/quando stai iniettando nuovi elementi DOM) è difficile rispondere con il modo migliore di occuparsene. Potrebbe essere, dopo aver esaminato la tua attuale soluzione, che qualcuno può indicare un modo per non dover iniettare i nuovi elementi o ha una soluzione alternativa per ciò che stai cercando di fare. –

risposta

35

Ogni volta che si richiama ko.applyBindings l'intera DOM è ispezionato per attacchi. Di conseguenza otterrai più associazioni per ciascun elemento se lo fai più di una volta. Se si desidera solo per associare un nuovo elemento DOM è possibile passare questo elemento come un parametro alla funzione applyBindings:

ko.applyBindings(viewModelA, document.getElementById("newElement")); 

Vai a questa domanda relativa:

Can you call ko.applyBindings to bind a partial view?

+1

Sì, questa è la soluzione che mi è venuta in mente :) Purtroppo non ho trovato una documentazione diretta dell'API su knockoutjs.com e ho dovuto eseguire alcune operazioni di reverse engineering sull'oggetto ko per scoprirlo. - –

+1

Vero, non c'è Documentazione API, ma è nella documentazione più "verbosa". Guarda a metà di questa pagina: http://knockoutjs.com/documentation/observables.html – ColinE

+0

Sei sicuro che questa sia la risposta? Non applicherebbe viewModelA al newElement come se newElement fosse la radice del DOM per viewModelA? Posso vedere dove funzionerebbe un po 'o anche più volte, ma posso anche vedere come potrebbero essere i risultati del prodotto non previsti (credo). –

7

Senza sapere che cosa sei fino a esattamente, sembra che tu stia andando nella direzione sbagliata. La tua vista dovrebbe essere guidata dal tuo modello di vista. Quindi non dovresti aggiungere direttamente elementi DOM a cui devi applicare i collegamenti a eliminazione diretta.

Invece dovresti aggiornare il tuo modello di vista per riflettere il cambiamento nella vista, che quindi fa apparire il tuo nuovo elemento.

Ad esempio, per il tuo $('body').append('<a href="#" data-bind="click: something">Click me!</a>');, anziché aggiungere l'elemento DOM quando il pulsante deve essere visibile, controlla la visibilità del pulsante utilizzando il modello di visualizzazione.

Così il vostro modello di vista include

var viewModel = { clickMeAvailable: ko.observable(false) } 

E il codice HTML include

<a href="#" data-bind="click: something, visible: clickMeAvailable">Click me!</a> 

quando cambia lo stato di applicazione in modo che il pulsante di click me è disponibile, è quindi solo viewModel.clickMeAvailable(true).

Il punto di questo e di gran parte del knockout è separare la logica aziendale dalla presentazione. Quindi il codice che rende cliccabile su di me non teme che il click me coinvolga un pulsante. Tutto ciò che fa è aggiornare viewModel.clickMeAvailable quando clicchi è disponibile.

Ad esempio, fare clic su di me è un pulsante Salva che dovrebbe essere disponibile quando un modulo viene compilato in modo valido. Collegherebbe la visibilità del pulsante di salvataggio a un modello di vista formValid osservabile.

Ma poi si decide di cambiare le cose quindi dopo che il modulo è valido, appare un accordo legale che deve essere consentito a prima di salvare. La logica del modulo non cambia, ma imposta lo formValid quando il modulo è valido. Dovresti solo cambiare ciò che accade quando si modificano le modifiche formValid.

Come lassombra sottolinea nei commenti su questa risposta, ci sono casi in cui la manipolazione diretta del DOM può essere il vostro approccio migliore - ad esempio una pagina dinamica complessa in cui si desidera solo idratare parti della vista quando sono necessarie. Ma stai abbandonando parte della separazione delle preoccupazioni che Knockout fornisce in questo modo. Stai attento se stai pensando di fare questo scambio.

+0

Mentre sono certamente d'accordo con tutto questo, penso che ci siano momenti in cui ha senso sfruttare i knockoutjs in modo da finire con i modelli di visualizzazione" annidati ". Questo potrebbe essere più sulla falsariga della situazione cristiana Nel qual caso dovresti avere un modello di visualizzazione che è specificamente impostato e associato al tuo HTML nidificato (presumibilmente inserito tramite ajax) quando è disponibile/ha terminato il caricamento. – Jed

+0

Per la cronaca, penso che questo sia la risposta corretta Il controllo dovrebbe essere vincolato alla dichiarazione, non guidato dal comportamento dell'evento Knockout è una di quelle tecnologie in cui è necessario mantenere l'intero approccio coerente per evitare fastidiosi bug al minimo –

+3

Che dire di siti particolarmente grandi dove la vista sta cambiando? Dovrebbero essere impacchettate tutte le viste possibili nella pagina di default? Sicuramente no. Caricare una vista tramite ajax mentre passi ad altre "aree" del sito è sicuramente un azione accettabile (io personalmente sto usando questo in un'applicazione web che sto convertendo. L'applicazione originale è MVC4 e ha diverse visualizzazioni per i diversi dati di gestione personale che stavo monitorando (azioni, altri dati finanziari, elenco di cose da fare, elenco contatti, calendario eventi). Dal momento che tutti usano la stessa pagina master, convertirli in MVVM/knockout è piuttosto semplice. – lassombra

0

So che l'hai chiesto molto tempo fa ma mi sono imbattuto in un problema simile. Ho provato ad aggiungere nuovi elementi al contenitore e dare loro una funzione onclick. All'inizio ho provato le cose che hai fatto, e ho anche provato l'approccio ColinErecommended. Questa non era una soluzione pratica per me, così ho provato SamStephens approccio e si avvicinò con quella, che workes perfettamente per me:

HTML:

<div id="workspace" data-bind="foreach:nodeArr, click:addNode"> 
<div class="node" data-bind="attr:{id:nodeID},style:{left:nodeX,top:nodeY},text:nodeID, click:$parent.changeColor"></div> 
</div> 

JavaScript:

<script> 
function ViewModel() { 
var self = this; 
var id = 0; 
self.nodeArr = ko.observableArray(); 
self.addNode = function (data, event) { 
    self.nodeArr.push({ 
     'nodeID': 'node' + id, 
     'nodeX' : (event.offsetX - 25) + 'px', 
     'nodeY' : (event.offsetY - 10) + 'px' 
    }) 
    id++; 
} 
self.changeColor = function(data, event){ 
    event.stopPropagation(); 
    event.target.style.color = 'green'; 
    event.target.style.backgroundColor = 'white'; 
} 
} 
ko.applyBindings(new ViewModel()); 
</script> 

Puoi giocare con esso nel JS Fiddle che ho fatto. Spero che questo aiuti ancora qualcuno.

+1

Beh, per me ... Ho abbandonato KnockoutJS molto tempo fa poiché era troppo poco flessibile per i miei scopi. –

+0

@ChristianEngel KO non è affatto flessibile .. certe cose devono essere fatte in modo KO (devo ancora trovare il bisogno di rifondare!) Per essere divertente, ma [Durandal] (http://durandaljs.com) (che usa KO) -> impressionante flessibilità con il supporto per le viste - le viste separate attenuano efficacemente la necessità di provare manualmente a legare parzialmente come ogni presentazione può introdurre o introdurre il proprio modello o condividere [parte di] un modello. Ora, ci sono alcune cose su KO che non mi piacciono, ma non ha nulla a che fare con la mancanza di flessibilità! Il modello osservabile è * molto * flessibile una volta che è completamente utilizzato. – user2246674

+0

@ChristianEngel Il modo "hackish ma facile" per gestire elementi (esterni) casuali iniettati nel DOM è quello di inserirli in un vincolo * control control * come 'if' (questo post mostra' foreach', che è probabilmente più pulito per iniziare con) e quindi attivare il contenuto "on" dopo che gli elementi sono stati inseriti - la nuova sottostruttura si legherà solo come appropriato. Non c'è * nessun * manuale aggiuntivo 'applyBindings' e un osservabile controlla l'associazione del flusso. È possibile utilizzare ulteriori collegamenti come "withProperties" per perfezionare le proprietà nell'ambito. – user2246674

Problemi correlati