KnockOutJS - wiele modeli ViewModels w jednym widoku


201

Myślę, że moja aplikacja robi się teraz dość duża, zbyt duża, aby obsłużyć każdy widok za pomocą jednego ViewModel.

Zastanawiam się więc, jak trudno byłoby stworzyć wiele modeli ViewModels i załadować je wszystkie do jednego widoku. Z notatką, że muszę również móc przekazywać dane X ViewModel do danych Y ViewModel, aby poszczególne ViewModels mogły komunikować się ze sobą lub przynajmniej być świadome siebie.

Na przykład mam listę <select>rozwijaną, ta lista rozwijana ma wybrany stan, który pozwala mi przekazać identyfikator wybranego elementu w <select>innym wywołaniu Ajax w osobnym ViewModel ....

Doceniono wszelkie punkty związane z obsługą wielu modeli ViewModels w jednym widoku :)


12
Osoby przybywające na to pytanie przewiń obok zaakceptowanej odpowiedzi. Knockout obsługuje teraz wiele kontekstów wiązania . Gigant nie potrzebuje masterVM.
Carrie Kendall,

Odpowiedzi:


150

Jeśli wszystkie muszą znajdować się na tej samej stronie, jednym z łatwych sposobów jest utworzenie modelu widoku głównego zawierającego tablicę (lub listę właściwości) innych modeli widoku.

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

W masterVMrazie potrzeby możesz mieć inne właściwości dla samej strony. W tej sytuacji komunikacja między modelami widoku nie byłaby trudna, ponieważ można było przechodzić przez masterVMlub można było używać powiązań $parent/ $rootin lub innych niestandardowych opcji.


2
Więc czy byłbym w stanie zrobić coś takiego: data-bind = "text: masterVM.vmA", przypuszczam, że nadal mógłbym używać ko.applyBindings z dołączonym elementem DOM. Załóżmy, że oznaczałoby to również, że mógłbym to zrobić: data-bind = "$ parent.masterVm"?
CLiown,

12
@CLiown Możesz użyć with:wiązania, aby się nie powtarzać
AlfeG

4
@CLiown Tak, możesz to zrobić, jeśli jesteś związany z masterVM. Możesz także użyć wiązania „z”, aby uniknąć składni kropek podczas zanurzania się w modelach widoku podrzędnego.
John Papa,

1
Myślę, że to podejście jest bardzo restrykcyjne ... Teraz w moim przypadku używam ASP.Net MVC4, to nie pomaga, ponieważ będą częściowe widoki posiadające własne modele ViewModels, a częściowe / sekcje treści nie powinny ze sobą kolidować , a ze względu na renderowanie warunkowe Korzystanie z tego podejścia będzie naprawdę trudne.
bhuvin

1
@bhuvin przy użyciu <! - ko stopBinding: true -> pomoże ci z wieloma modelami widoków i sekcjami widoków częściowych. Aby uzyskać więcej informacji, zobacz knockmeout.net/2012/05/quick-tip-skip-binding.html .
Micaël Félix

285

Knockout obsługuje teraz wiązanie wielu modeli. Theko.applyBindings()Sposobie, opcjonalny parametr - element i jego potomstwo, które są natychmiast aktywowany.

Na przykład:

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

Ogranicza to aktywację do elementu o identyfikatorze someElementIdi jego potomkach.

Więcej informacji znajduje się w dokumentacji .


72
Jeśli chcesz użyć selektora jQuery, musisz dodać, [0]aby określić rzeczywisty element DOM (zamiast obiektu jQuery) w następujący sposób:ko.applyBindings(myViewModel, $('#someElementId')[0])
MrBoJangles

3
To powinna być zaakceptowana odpowiedź. Nadal możesz użyć obiektu głównego, tak jak ma obecnie akceptowana odpowiedź, a następnie powiązać poszczególne modele widoku z odpowiednimi elementami na stronie. Pozwoli to zaoszczędzić na wydajności i ograniczy zakres wymagany do wiązania danych.
Kevin Heidt

Czy możliwe jest wzajemne komunikowanie się viewModels z tym podejściem? tzn. mam TaskVM i NoteVM. Zadanie może mieć notatki. Dlatego moja TaskVM musi mieć tablicę obserwowalną, a mianowicie notatki, których typem jest TaskVM. Czy możesz podać przykład takiej sprawy?
Ahmet

Prawdopodobnie najlepiej zapytać o komunikację między maszynami wirtualnymi w nowym pytaniu.
Richard Należyski

21

To moja odpowiedź po ukończeniu bardzo dużego projektu z dużą ilością ViewModels w jednym widoku.

Widok HTML

    <!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>

Dla tego widoku tworzę 2 modele widoków dla id = kontener1 i id = kontener2 w dwóch osobnych plikach javascript.

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");

}

Następnie po tych 2 modelach rejestracji rejestrują się jako osobne modele w 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"));
    }
});

W ten sposób możesz dodać dowolną liczbę modeli widoku dla oddzielnych div. Ale upewnij się, że nie twórz osobnego modelu widoku dla div wewnątrz zarejestrowanego div.


Czy można zrobić coś w rodzaju viewmodel wewnątrz innych zamiast być oddzielnymi elementami DOM?
UserEsp

4

Sprawdź wtyczkę MultiModels pod kątem Knockout JS - https://github.com/sergun/Knockout-MultiModels


6
Jakie to ma przewagę nad ko.applyBindings (viewModel, document.getElementById („divName”))? Czy to nie tylko cukier syntaktyczny?
Paolo del Mundo,

1
@Paolo del Mundo Dodaje także zależność od wtyczki LiveQuery.
Lars Gyrup Brink Nielsen,

@PaolodelMundo celem wtyczki jest możliwość korzystania z zestawu modeli widoków w sposób odważny
Sergey Zwezdin

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.