web-dev-qa-db-fra.com

knockout.js: mettre à jour les liaisons?

lorsque j'injecte de nouveaux éléments dans le DOM après ko.applyBindings (); a été appelé, alors knockout ne reconnaîtra pas ces nouveaux éléments ... Je peux comprendre pourquoi cela se produit - ils ne sont tout simplement pas indexés par knock-out.

Donc, au début, j'ai pensé que cela serait résolu en appelant à nouveau ko.applyBindings (), après avoir ajouté mes nouveaux éléments, MAIS j'ai réalisé que pour chaque appel ko.applyBindings () que vous passez, les événements correspondants sont déclenchés plusieurs fois. Donc, après avoir appliqué cinq fois, un clic: la reliure sera déclenchée cinq fois, ce n'est donc pas une solution souhaitable;)

Y a-t-il quelque chose comme ko.updateBindings () ou autre chose, à dire à knock-out, et bien ... mettre à jour les liaisons d'éléments?

salutations, Chris

36
Christian Engel

Chaque fois que vous appelez ko.applyBindings, tout le DOM est soumis à une inspection. En conséquence, vous obtiendrez plusieurs liaisons pour chaque élément si vous le faites plus d'une fois. Si vous souhaitez simplement lier un nouvel élément DOM, vous pouvez passer cet élément en tant que paramètre à la fonction applyBindings:

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

Voir cette question connexe:

Pouvez-vous appeler ko.applyBindings pour lier une vue partielle?

36
ColinE

Sans savoir ce que vous faites exactement, il semble que vous vous trompiez de sujet. Votre vue doit être guidée par votre modèle de vue. Par conséquent, vous ne devriez pas ajouter directement des éléments DOM auxquels vous devez ensuite appliquer des liaisons de masquage.

Au lieu de cela, vous devriez mettre à jour votre modèle de vue pour refléter le changement dans la vue, ce qui entraîne l'affichage de votre nouvel élément.

Ainsi, par exemple, pour votre $('body').append('<a href="#" data-bind="click: something">Click me!</a>');, plutôt que d'ajouter l'élément DOM lorsque le bouton doit être visible, contrôlez la visibilité du bouton à l'aide du modèle de vue.

Donc, votre modèle de vue comprend

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

Et votre HTML comprend

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

Lorsque l'état de l'application change et que le bouton «Cliquez sur moi» est disponible, il vous reste alors viewModel.clickMeAvailable(true).

Pour ce faire, il est essentiel de séparer la logique d’entreprise de la présentation. Donc, le code qui rend click me disponible n'a pas d'importance que click me implique un bouton. Il ne fait que mettre à jour viewModel.clickMeAvailable lorsque click me est disponible.

Par exemple, cliquez sur moi est un bouton de sauvegarde qui devrait être disponible lorsqu'un formulaire est rempli de manière valide. Vous lieriez la visibilité du bouton de sauvegarde à un modèle de vue formValid observable.

Mais ensuite, vous décidez de changer les choses pour que, une fois le formulaire validé, un accord juridique apparaisse auquel vous devez consentir avant de sauvegarder. La logique de votre formulaire ne change pas - elle définit toujours formValid lorsque le formulaire est valide. Vous voudriez simplement changer ce qui se passe lorsque formValid change.

Comme lassombra le souligne dans les commentaires sur cette réponse, il est parfois préférable de recourir à la manipulation directe du DOM, par exemple une page dynamique complexe pour laquelle vous souhaitez uniquement hydrater certaines parties de la vue selon vos besoins. Mais vous abandonnez certaines des préoccupations de séparation que Knockout fournit en procédant ainsi. Soyez conscient si vous envisagez de faire ce compromis.

7
SamStephens

Je sais que vous avez demandé il y a longtemps, mais je suis tombé sur un problème similaire. J'ai essayé d'ajouter de nouveaux éléments au conteneur et de leur donner une fonction onclick. Au début, essayez ce que vous avez fait et même l’approche ColinErecommandé . Ce n'était pas une solution pratique pour moi alors j'ai essayé SamStephens et je l'ai trouvé, ce qui fonctionne parfaitement pour moi:

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>

Vous pouvez jouer avec cela dans le JS Fiddle I made . J'espère que cela aide toujours quelqu'un.

0
Maximilian Lindsey