2017-01-26 4 views
1

(ich weiß, der Titel nicht die beste ist - fühlen Sie sich frei, es zu bearbeiten)

JSFiddle for easy testing

Ich habe folgende Knockout.js sehen Modell:

function Bar() { 
    var self = this; 
    self.baz = "baz"; 
} 

function Foo() { 
    var self = this; 
    self.bars = ko.observableArray([]); 

    self.addBar = function() { self.bars.push(new Bar()); }; 
    self.removeBar = function (bar) { self.bars.remove(bar); }; 
} 

function ViewModel() { 
    var self = this; 
    self.foo = new Foo(); 
} 

ko.applyBindings(new ViewModel()); 

und die folgende HTML:

<a href="#" data-bind="click: foo.addBar">Add</a> 

<ul data-bind="foreach: foo.bars"> 
    <li><span data-bind="text: baz"></span> <a href="#" data-bind="click: $root.foo.removeBar">Remove</a></li> 
</ul> 

Dies funktioniert wie erwartet. Aber wenn ich den absoluten Pfad ändern $root.foo.removeBar-$parent.removeBar etwa so:

<a href="#" data-bind="click: $parent.removeBar">Remove</a> 

Artikel Entfernung nicht mehr funktioniert; Ich sehe jedoch keine Fehler auf der Konsole.

Mit etwas Experimentieren, kann ich feststellen, dass $parent hier zum aktuellen Elemente im beobachtbaren Array bezieht sie (a Bar Beispiel), nicht das enthaltende Objekt (ein Foo Beispiel).

Meine Frage ist: Wie kann ich auf das enthaltende Objekt verweisen, indem ich eine relative Referenz in meinen Bindungen verwende?

EDIT: Ich habe einen Weg gefunden, das funktioniert:

<!-- ko with: foo --> 
<ul data-bind="foreach: bars"> 
    <li> 
     <span data-bind="text: baz"></span> 
     <a href="#" data-bind="click: $parent.removeBar">Remove</a> 
    </li> 
</ul> 
<!-- /ko --> 

Es ist nicht schön, aber es funktioniert. Es läuft im Grunde darauf hinaus, einen neuen Spielraum für die foo Eigenschaft vor der foreach zu öffnen.

Also meine nächste Frage ist: gibt es eine bessere Möglichkeit, dies zu tun?

Antwort

2

Knockout-Bindungskontexte werden jedes Mal erstellt, wenn Sie eine Kontrollflussbindung wie 'mit' oder 'foreach' "(reference) verwenden. Ich denke also, die Verwirrung besteht darin, dass die Bindungshierarchie durch das HTML und nicht durch Ihr Ansichtsmodell bestimmt wird. In Ihrer Sicht Modell die Hierarchie ist ViewModel -> Foo -> Bars, aber in der Markup gibt es $ root, die ViewModel ist, und dann der nächste Kontext, der erstellt wird, ist für die Bars Objekt, so dass seine Eltern direkt auf das ViewModel so zugeordnet wird Foo überspringen.

Soweit ein besserer Weg ... Ich habe eigentlich nichts dagegen, mit der Bindung, die Sie haben, ich denke, es macht den Code sauberer als auf jeder Bindung in foo Drill. Besser ist in diesem Fall die reine Meinung. Sie könnten alternativ $ parent.foo.removeBar anstelle von $ root.foo.removeBar verwenden, wissend, dass sich diese in Ihrem Kontext auf dasselbe beziehen. Eine dritte Option wäre, Foo selbst als Root-View-Modell zu verwenden, da es in diesem Beispiel nicht viel mehr zu tun scheint als das Servieren von Foo, aber vielleicht ist Ihr tatsächlicher Anwendungsfall komplizierter.

+0

Dank @JasonSpake, großartige Erklärung! Mein tatsächlicher Anwendungsfall ist in der Tat viel komplizierter und es ist wichtig, nicht vom vollständigen Pfad zu den Eigenschaften abhängig zu sein (ich verwende verschiedene Hilfsfunktionen, die Teile des HTML erzeugen). –

Verwandte Themen