it-swarm.com.de

knockout.js: Bindungen aktualisieren?

wenn ich nach ko.applyBindings () neue Elemente in das DOM einspreche; wurde aufgerufen, dann wird der Knockout diese neuen Elemente nicht erkennen ... Ich kann verstehen, warum dies geschieht - sie werden einfach nicht durch den Knockout indiziert.

Zuerst dachte ich, dass dies gelöst werden würde, indem einfach nur noch ko.applyBindings () aufgerufen wurde. Nachdem ich meine neuen Elemente hinzugefügt hatte, wurde mir jedoch klar, dass bei jedem Aufruf von ko.applyBindings () die entsprechenden Ereignisse mehrfach ausgelöst werden. Nach fünfmaliger Anwendung wird also ein Klick ausgelöst: Die Bindung wird fünfmal ausgelöst, daher ist dies keine wünschenswerte Lösung;)

Gibt es etwas wie ko.updateBindings () oder etwas anderes, um dem Knockout mitzuteilen, na ja ... die Elementbindungen aktualisieren?

grüße, Chris

36
Christian Engel

Bei jedem Aufruf von ko.applyBindings wird das gesamte DOM auf Bindungen geprüft. Als Ergebnis erhalten Sie mehrere Bindungen für jedes Element, wenn Sie dies mehr als einmal tun. Wenn Sie nur ein neues DOM-Element binden möchten, können Sie dieses Element als Parameter an die applyBindings-Funktion übergeben:

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

Siehe diese verwandte Frage:

Kannst du ko.applyBindings aufrufen, um eine Teilansicht zu binden?

36
ColinE

Ohne zu wissen, was Sie genau vorhaben, scheint es, als würden Sie dabei den falschen Weg gehen. Ihre Ansicht sollte von Ihrem Ansichtsmodell gesteuert werden. Sie sollten also nicht direkt DOM-Elemente hinzufügen, für die Sie dann Knockout-Bindungen anwenden müssen.

Stattdessen sollten Sie Ihr Ansichtsmodell aktualisieren, um die Änderung in der Ansicht widerzuspiegeln, woraufhin Ihr neues Element angezeigt wird.

Steuern Sie beispielsweise für Ihr $('body').append('<a href="#" data-bind="click: something">Click me!</a>'); das DOM-Element, wenn die Schaltfläche sichtbar sein soll, mit dem Ansichtsmodell.

So umfasst Ihr Ansichtsmodell

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

Und dein HTML enthält

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

Wenn sich der Anwendungsstatus ändert und der Klick-Button verfügbar ist, können Sie einfach viewModel.clickMeAvailable(true) aufrufen.

Dies und ein großer Teil des Knockouts sind die Trennung der Geschäftslogik von der Präsentation. Daher ist es für den Code, der Click me verfügbar macht, egal, dass Click me eine Schaltfläche beinhaltet. Alles, was es tut, ist viewModel.clickMeAvailable zu aktualisieren, wenn click me verfügbar ist.

Angenommen, "Klicken" ist eine Schaltfläche zum Speichern, die verfügbar sein sollte, wenn ein Formular gültig ausgefüllt wird. Sie würden die Sichtbarkeit der Schaltfläche "Speichern" mit einem beobachtbaren Modell "formValid" verknüpfen.

Aber dann entscheiden Sie sich für eine Änderung, so dass nach der Gültigkeit des Formulars eine rechtliche Vereinbarung erscheint, der vor dem Speichern zugestimmt werden muss. Die Logik Ihres Formulars ändert sich nicht - es setzt immer noch formValid, wenn das Formular gültig ist. Sie würden einfach ändern, was passiert, wenn formValid sich ändert.

Wie Lassombra in den Kommentaren zu dieser Antwort hervorhebt, gibt es Fälle, in denen eine direkte DOM-Manipulation der beste Ansatz ist - zum Beispiel eine komplexe dynamische Seite, auf der Sie nur Teile der Ansicht nach Bedarf hydrieren möchten. Aber Sie geben etwas von der Trennung der Bedenken auf, die Knockout bietet, indem Sie dies tun. Seien Sie vorsichtig, wenn Sie dies in Erwägung ziehen.

7
SamStephens

Ich weiß, Sie haben vor langer Zeit gefragt, aber ich bin gerade auf ein ähnliches Problem gestoßen. Ich habe versucht, dem Container neue Elemente hinzuzufügen und diesen eine Onclick-Funktion zu geben. Zuerst haben Sie die Dinge ausprobiert, die Sie getan haben, und sogar den Ansatz ColinEempfohlen . Dies war keine praktikable Lösung für mich, also versuchte ich SamStephens Herangehen und habe mir das ausgedacht, was für mich perfekt funktioniert:

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>

Sie können damit in der JS Fiddle ich habe ..__ gespielt. Hoffe, das hilft noch jemandem.

0