2012-02-15 5 views
189

Myślę, że moja aplikacja jest teraz dość duża, zbyt duża, aby obsłużyć każdy widok za pomocą pojedynczego ViewModel.KnockOutJS - wiele modeli ViewModels w jednym widoku

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

Na przykład mam <select> rozwijaną, że rozwijanej wybierz ma wybrany stan, który pozwala mi przekazać identyfikator wybranego elementu w <select> do innego połączenia Ajax w oddzielnym ViewModel ....

Dowolne punkty dotyczące radzenia sobie z wieloma ViewModels w jednym Widoku docenionym :)

+11

Dla osób przybywających na to pytanie, przewiń obok zaakceptowanej odpowiedzi. [Knockout obsługuje teraz wiele kontekstów bindowania] (http://stackoverflow.com/a/11572094/998328). Nie ma potrzeby używania gigantycznego "masterVM". –

Odpowiedz

145

Jeśli wszystkie muszą znajdować się na tej samej stronie, jednym prostym sposobem na wykonanie tego jest posiadanie 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ówczas masterVM może mieć inne właściwości, w razie potrzeby, na samej stronie. Komunikacja między modelami widoków nie byłaby trudna w tej sytuacji, ponieważ można było przekazywać komunikaty za pośrednictwem masterVM lub można użyć w powiązaniach lub innych niestandardowych opcji.

+2

Byłbym w stanie zrobić coś takiego: data-bind = "text: masterVM.vmA", Przypuszczam, że nadal mógłbym użyć ko.applyBindings z dołączonym elementem DOM. Załóżmy, że to również oznacza, że ​​mogę zrobić: data-bind = "$ parent.masterVm"? – CLiown

+12

@CLiown Możesz użyć 'with:' bindowania, więc nie powtórzysz siebie – AlfeG

+4

@ CLiown Tak, możesz to zrobić, jeśli przywiążesz masterVM. Możesz także użyć wiązania "z", aby uniknąć składni kropek podczas nurkowania w modelach podrzędnych. –

3

Sprawdź MultiModels plugin dla Knockout JS - https://github.com/sergun/Knockout-MultiModels

+6

Jaka jest ta przewaga nad ko.applyBindings (viewModel, document.getElementById ("divName"))? Czy to nie jest tylko cukier syntaktyczny? –

+1

@Paolo del Mundo Dodaje także zależność od wtyczki LiveQuery. –

+0

@PaolodelMundo celem wtyczki jest możliwość użycia zestawu modeli podglądu w sposób dekalacyjny –

281

Knockout teraz obsługuje wiele model wiązania. Metoda ko.applyBindings() przyjmuje opcjonalny parametr - element i jego potomkowie, do którego będzie aktywowane wiązanie.

Na przykład

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

Ogranicza to aktywację na element o ID someElementId i jej potomstwa.

Aby uzyskać więcej informacji, patrz documentation.

+68

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

+2

To powinna być zaakceptowana odpowiedź. Nadal można używać obiektu wzorcowego, takiego jak aktualnie zaakceptowana odpowiedź, a następnie powiązać poszczególne modele widoków z odpowiednimi elementami na stronie. Pozwoli to zaoszczędzić na wydajności i ograniczy zakres potrzebny do powiązania danych. –

+0

Czy jest możliwe komunikowanie się z viewModels za pomocą tego podejścia? tj. mam TaskVM i NoteVM. Zadanie może mieć notatki. Dlatego moja TaskVM musi mieć obserwowalną tablicę, a mianowicie notatki, których typem jest TaskVM. Czy możesz udostępnić przykład takiego przypadku? – ahmet

18

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

HTML Zobacz

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

Z tego względu tworzę 2 Widok modeli id ​​= container1 i id = container2 w dwóch oddzielnych 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 ViewModels rejestrujesz jako oddzielne ViewModels 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")); 
    } 
}); 

Jak to można dodać dowolna liczba modeli podglądu dla osobnych elementów div.Ale upewnij się, że nie tworzysz osobnego modelu widoku dla elementu div wewnątrz zarejestrowanego elementu div.