KnockOutJS - Mehrere ViewModels in einer einzigen Ansicht


201

Ich denke, dass meine Anwendung jetzt ziemlich groß wird, zu groß, um jede Ansicht mit einem einzelnen ViewModel zu verarbeiten.

Ich frage mich also, wie schwierig es wäre, mehrere ViewModels zu erstellen und sie alle in eine einzige Ansicht zu laden. Mit dem Hinweis, dass ich auch in der Lage sein muss, X ViewModel- Daten an Y ViewModel- Daten zu übergeben, damit die einzelnen ViewModels miteinander kommunizieren oder sich zumindest bewusst sein können.

Zum Beispiel habe ich ein <select>Dropdown-Menü. Dieses Auswahl-Dropdown-Menü hat einen ausgewählten Status, mit dem ich die ID des ausgewählten Elements in <select>einem anderen Ajax-Aufruf in einem separaten ViewModel übergeben kann.

Alle Punkte zum Umgang mit zahlreichen ViewModels in einer einzigen Ansicht sind willkommen :)


12
Wenn Sie zu dieser Frage kommen, scrollen Sie bitte über die akzeptierte Antwort hinaus. Knockout unterstützt jetzt mehrere Bindungskontexte . Es ist kein Riese nötig masterVM.
Carrie Kendall

Antworten:


150

Wenn sich alle auf derselben Seite befinden müssen, besteht eine einfache Möglichkeit darin, ein Hauptansichtsmodell zu haben, das ein Array (oder eine Eigenschaftsliste) der anderen Ansichtsmodelle enthält.

masterVM = {
    vmA : new VmA(),
    vmB : new VmB(),
    vmC : new VmC(),
}

Dann masterVMkönnen Sie bei Bedarf andere Eigenschaften für die Seite selbst haben. Die Kommunikation zwischen den Ansichtsmodellen wäre in dieser Situation nicht schwierig, da Sie masterVMdie $parent/ $rootin-Bindungen weiterleiten oder die / in-Bindungen oder andere benutzerdefinierte Optionen verwenden könnten .


2
Wäre ich also in der Lage, etwas wie: data-bind = "text: masterVM.vmA" zu tun, könnte ich ko.applyBindings wahrscheinlich weiterhin mit dem angehängten DOM-Element verwenden. Angenommen, das würde auch bedeuten, dass ich Folgendes tun könnte: data-bind = "$ parent.masterVm"?
CLiown

12
@ CLiown Sie können with:Bindung verwenden, so dass Sie sich nicht wiederholen werden
AlfeG

4
@CLiown Ja, das können Sie tun, wenn Sie an die masterVM gebunden sind. Sie können auch die "with" -Bindung verwenden, um die Punktsyntax beim Eintauchen in die Unteransichtsmodelle zu vermeiden.
John Papa

1
Ich denke, dieser Ansatz ist sehr restriktiv ... In meinem Fall verwende ich ASP.Net MVC4. Dies hilft nicht, da es Teilansichten mit eigenen ViewModels gibt und die Teil- / Inhaltsabschnitte sich nicht gegenseitig stören sollten und aufgrund des bedingten Renderns wird es wirklich schwierig sein, diesen Ansatz zu verwenden.
Bhuvin

1
@bhuvin mit <! - ko stopBinding: true -> hilft Ihnen bei diesen Abschnitten mit mehreren Ansichten und Teilansichten. Weitere Informationen finden Sie unter knockmeout.net/2012/05/quick-tip-skip-binding.html .
Micaël Félix

285

Knockout unterstützt jetzt die Bindung mehrerer Modelle. Die ko.applyBindings()Methode verwendet einen optionalen Parameter - das Element und seine Nachkommen, für die die Bindung aktiviert wird.

Beispielsweise:

ko.applyBindings(myViewModel, document.getElementById('someElementId'))

Dies beschränkt die Aktivierung auf das Element mit der ID someElementIdund seinen Nachkommen.

Weitere Informationen finden Sie in der Dokumentation .


72
Wenn Sie einen jQuery-Selektor verwenden möchten, möchten Sie hinzufügen [0], um ein tatsächliches DOM-Element (anstelle des jQuery-Objekts) wie ko.applyBindings(myViewModel, $('#someElementId')[0])
folgt anzugeben

3
Dies sollte die akzeptierte Antwort sein. Sie können weiterhin ein Master-Objekt wie die aktuell akzeptierte Antwort verwenden und dann die einzelnen Ansichtsmodelle an die entsprechenden Elemente auf der Seite binden. Dies spart Leistung und schränkt den für die Datenbindung erforderlichen Umfang ein.
Kevin Heidt

Ist es mit diesem Ansatz möglich, viewModels miteinander zu kommunizieren? dh ich habe TaskVM und NoteVM. Aufgabe kann Notizen haben. Daher muss meine TaskVM ein ObservableArray haben, nämlich Notizen, deren Typ TaskVM ist. Können Sie ein Beispiel für einen solchen Fall nennen?
ahmet

Es ist wahrscheinlich am besten, in einer neuen Frage nach der Kommunikation zwischen VMs zu fragen.
Richard Nalezynski

21

Dies ist meine Antwort, nachdem ich ein sehr großes Projekt mit vielen ViewModels in einer Ansicht abgeschlossen habe.

HTML-Ansicht

    <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
    <div id="container1">
        <ul>
            <li >Container1 item</li>
            <!-- ko foreach: myItems -->
            <li>Item <span data-bind="text: $data"></span></li>
            <!-- /ko -->
        </ul>
    </div>

    <div id="container2">
        <ul>
            <li >Container2 item</li>
            <!-- ko foreach: myItems -->
                <li>Item <span data-bind="text: $data"></span></li>
            <!-- /ko -->
        </ul>
    </div>

    <script src="js/jquery-1.11.1.js"></script>
    <script src="js/knockout-3.0.0.js"></script>
    <script src="js/DataFunction.js"></script>
    <script src="js/Container1ViewModel.js"></script>
    <script src="js/Container2ViewModel.js"></script>

</body>
</html>

Für diese Ansicht erstelle ich zwei Ansichtsmodelle für id = container1 und id = container2 in zwei separaten Javascript-Dateien.

Container1ViewModel.js

function Container1ViewModel()
{
    var self = this;
    self.myItems = ko.observableArray();
    self.myItems.push("ABC");
    self.myItems.push("CDE");

} 

Container2ViewModel.js

function Container2ViewModel() {
    var self = this;
    self.myItems = ko.observableArray();
    self.myItems.push("XYZ");
    self.myItems.push("PQR");

}

Danach registrieren sich die beiden Ansichtsmodelle als separate Ansichtsmodelle in DataFunction.js

var container1VM;
var container2VM;

$(document).ready(function() {

    if ($.isEmptyObject(container1VM)) {
        container1VM = new Container1ViewModel();
        ko.applyBindings(container1VM, document.getElementById("container1"));
    }

    if ($.isEmptyObject(container2VM)) {
        container2VM = new Container2ViewModel();
        ko.applyBindings(container2VM, document.getElementById("container2"));
    }
});

Auf diese Weise können Sie eine beliebige Anzahl von Ansichtsmodellen für separate Divs hinzufügen. Stellen Sie jedoch sicher, dass Sie kein separates Ansichtsmodell für ein Div innerhalb des registrierten Div erstellen.


Ist es möglich, eine Art Ansichtsmodell innerhalb eines anderen zu erstellen, anstatt separate Elemente des DOM zu sein?
UserEsp

4

Überprüfen Sie das MultiModels-Plugin auf Knockout JS - https://github.com/sergun/Knockout-MultiModels


6
Welchen Vorteil hat dies gegenüber nur ko.applyBindings (viewModel, document.getElementById ("divName"))? Ist es nicht nur syntaktischer Zucker?
Paolo del Mundo

1
@Paolo del Mundo Es wird auch eine Abhängigkeit vom LiveQuery-Plugin hinzugefügt.
Lars Gyrup Brink Nielsen

@PaolodelMundo Der Zweck des Plugins ist es, eine Reihe von Ansichtsmodellen auf dekalrative Weise verwenden zu können
Sergey Zwezdin

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.