2014-02-25 13 views
7
Bindung

Lassen Sie uns einen Blick Modell wie die Verwendung von Knockout betrachten:Knockout JS Aufruf einer Ansichtsmodell Funktion innerhalb einer foreach

Mit dieser Ansicht:

<ul data-bind="foreach: items"> 
    <li><span data-bind="text: id"></span> 
     <span data-bind="visible: $root.showName(name)">Yes! show the name</span> 
     <a href="#" data-bind="click: $root.removePerson">Remove</a> 
    </li> 
</ul> 

Sie es hier in Aktion sehen können: http://jsfiddle.net/SmW35/8/

In diesem Fall, wenn jemand die „entfernen“ -Link, und KO ruft die Funktion showname, das Objekt „diese“ innerhalb der Funktion klickt, es ist ein Objekt mit dem aktuellen Element, zum Beispiel, wenn ich auf "Entfernen" in Punkt 2 klicke, ist "das" {ID: 2, Name: ""} Wenn jedoch KO das "Sichtbare" bindet und den showName aufruft Funktion, das Objekt "this" enthält nicht das aktuelle Element, und Sie müssen "name" an die Funktion übergeben (oder Sie könnten die $ data verwenden).

Also, ich habe 2 Fragen:

  • Es gibt einen Weg, um die showname Funktion aus der Sicht aufrufen, ohne den Namen oder $ Daten übergeben (ein ähnliches Verhalten als mit dem Link Entfernen)
  • Wenn nicht ist da etwas nicht in Ordnung? Ich habe eine interessante Diskussion mit einem Arbeitskollegen, der denkt, dass das nicht richtig ist, weil Sie Daten aus der Ansicht senden ($ root.showName (name)), und dann ist das kein "reines" MVVM-Muster. Er schlägt vor, eine benutzerdefinierte KO-Bindung zu erstellen, um die Funktionalität zu erreichen. Meiner Meinung nach fliegen Fliegen mit einem Panzer, aber ich bin sehr neugierig, ob es einen anderen Weg gibt oder du denkst auch, dass ich kein reines MVVM-Muster mit meinem Code mache.
+0

aus interesse warum würden sie den name span verstecken aber lassen sie die taste sichtbar. Wenn Sie beide ausblenden möchten, gibt es eine andere Lösung, die Luis beschreibt unter –

+0

@RobertSlaney die Schaltfläche zum Entfernen ist nur da, um zu helfen, zu verstehen, was ich gefragt habe. Es gibt keine Schaltfläche zum Entfernen in meinem Projekt, und der ShowName ist für andere Zwecke (aber genau die gleiche Einfachheit). Vielen Dank! –

Antwort

5

In gewissem Sinne hat Ihr Kollege einen Punkt. Ich persönlich würde jedoch keine benutzerdefinierte Bindung erstellen, um damit umzugehen. (Subjektiv gesehen sind benutzerdefinierte Bindungen eher dann gedacht, wenn es eine spezielle Art der Kommunikation zwischen Ansicht und Ansichtsmodell gibt; siehe this post für eine großartige Erklärung, wann sie zu verwenden sind).

Auf einer Seite beachten, wenn wir erkunden die Möglichkeit, eine benutzerdefinierte Bindung zu tun, ich denke, Sie so etwas wie ein textIfNotEmpty Bindungs ​​Handler tun können, die text und visible in einem vereint. Auf der anderen Seite, wenn die showName Funktionalität so einfach bleibt, wie es ist, dass Sie auch gehen könnte:

<span data-bind="visible: !!name, text: name"></span> 

Auf jeden Fall würde ich die folgende bevorzugen ...

Das zugrunde liegende Problem ist IMO dass das View-Modell gegen das Prinzip der einheitlichen Verantwortlichkeit verstößt: Die showName-Funktionalität sollte in der Verantwortung eines View-Modells liegen, das ein Element darstellt.

var Item = function(data) { 
    var self = this; 

    self.id = data.id; 

    self.name = ko.observable(data.name); 
    // or plain "self.name = data.name;" if you don't need 2way binding 

    self.showName = ko.computed(function() { 
     return self.name() && self.name().length > 0; 
    }); 
} 

Jetzt können Sie leicht wie diese binden:

<ul data-bind="foreach: items"> 
    <li><span data-bind="text: id"></span> 
     <span data-bind="visible: showName">Yes! show the name</span> 
     <a href="#" data-bind="click: $root.removePerson">Remove</a> 
    </li> 
</ul> 

Welche auch Sie die removePerson dazu umschreiben lässt:

viewModel.removePerson = function (person) { 
    console.log(person); 
}; 

Dieses Sie erfordert ein klein wenig zu tun zusätzliche Arbeit beim Aufbau des beobachtbaren Arrays, aber es lohnt sich, da es alle Bedenken klar trennt.Es könnte in dieser Richtung geschehen:

var viewModel = { 
    items: ko.observableArray(data.map(function(item) { return new Item(item); })) 
}; 

this fiddle für eine Demo des Siehe oben.

+0

vielen Dank. 2 Kommentare: 1) Ich denke, es gibt einen Fehler in der Ansicht, und das "visible: showName (name)" sollte "visible: showName()" sein. 2) Ich sehe nicht, dass meine Ansicht Logik hat, die Logik ist in der ShowName-Funktion. Die Ansicht sendet nur den Wert von Name. Jedenfalls verstehe ich dein Beispiel und ich kann zustimmen, dass MVVM reiner ist, aber auch mehr Arbeit. Nicht sicher, ob es sich lohnt. Danke noch einmal! –

+0

Ah ja, denke du hast in beiden Punkten Recht. In jedem Fall ist SO nicht sehr gut, um die subjektiven Bits zu diskutieren. Bitte betrachten Sie meine Antwort lediglich als eine alternative Möglichkeit, das zu erreichen, was Sie wollen. Es ist eine fallweise (subjektive) Entscheidung, mit welcher Vorgehensweise man letztendlich fortfahren kann. Viel Glück! – Jeroen

+0

PS. Wenn Sie Fehler oder Fehler in meinem Code finden, können Sie meine Antwort bearbeiten. – Jeroen

Verwandte Themen