2012-02-15 78 views
189

我在想我的應用程序現在變得相當大,太大而無法用一個ViewModel處理每個視圖。KnockOutJS - 單個視圖中的多個ViewModel

所以我想知道創建多個ViewModels並將它們全部加載到一個View中是多麼困難。注意,我還需要能夠將X ViewModel數據傳遞到Y ViewModel數據,因此各個ViewModel需要能夠相互通信或至少知道對方。

比如我有一個<select>下拉,用來選擇下拉有一個選擇的狀態,讓我通過所選擇的項目的ID在<select>在一個單獨的視圖模型另一個Ajax調用....

在單個視圖中處理大量視圖模型的任何觀點都會受到讚賞:)

+11

對於那些到達這個問題,請滾動通過接受的答案。 [Knockout現在支持多個綁定上下文](http://stackoverflow.com/a/11572094/998328)。不需要一個巨大的'masterVM'。 – 2015-04-10 16:04:59

回答

145

如果它們都需要位於同一頁面上,一個簡單的方法是使主視圖模型包含數組(或屬性列表)其他視圖模型。

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

那麼你masterVM可以在需要時針對網頁本身的其他屬性。視圖模型之間的通信在這種情況下並不困難,因爲您可以通過masterVM進行中繼,或者可以使用綁定中的$parent/$root或其他一些自定義選項。

+2

所以,我將能夠做到這樣的事情: data-bind =「text:masterVM.vmA」,我想我仍然可以使用附帶DOM元素的ko.applyBindings。 假設這也意味着我可以這樣做: data-bind =「$ parent.masterVm」? – CLiown 2012-02-15 14:23:10

+12

@CLiown你可以使用'with:'綁定,所以你不會重複自己 – AlfeG 2012-02-15 14:25:54

+4

@CLiown是的,你可以做到這一點,如果你綁定到masterVM。當您進入子視圖模型時,您還可以使用「with」綁定來幫助避免點語法。 – 2012-02-15 15:47:52

3

檢查MultiModels插件淘汰賽JS - https://github.com/sergun/Knockout-MultiModels

+6

這有什麼優勢,而不僅僅是ko.applyBindings(viewModel,document.getElementById(「divName」))?這不僅僅是語法糖嗎? – 2013-01-30 14:21:33

+1

@Paolo del Mundo 它還增加了對LiveQuery插件的依賴。 – 2013-12-30 10:07:24

+0

@PaolodelMundo插件的目的是爲了能夠以批准方式使用視圖模型集 – 2014-05-27 03:36:13

281

淘汰賽現在支持多個模型綁定。 ko.applyBindings()方法接受一個可選參數 - 綁定將被激活的元素及其後代。

例如:

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

這限制了激活的元件與ID someElementId及其後代。

有關更多詳細信息,請參見documentation

+68

如果你想使用jQuery選擇器,你需要添加'[0]'來指定一個實際的DOM元素(而不是jQuery對象)就像這樣:'ko.applyBindings(myViewModel,$('#someElementId')[0])' – MrBoJangles 2013-02-25 20:30:21

+2

這應該是被接受的答案。您仍然可以使用像當前接受的答案一樣的主對象,然後將各個視圖模型綁定到頁面上的相應元素。這將節省性能,並限制數據綁定所需的範圍。 – 2014-09-18 16:00:39

+0

是否有可能使用這種方法相互溝通viewModels?即我有TaskVM和NoteVM。任務可以有Notes。因此,我的TaskVM必須有一個observableArray,即類型爲TaskVM的註釋。你能分享一個這樣的案例的例子嗎? – ahmet 2016-03-08 22:16:35

18

這是我的答案完成非常大的項目與大量的ViewModels單視圖。

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> 

對於這個觀點,我在兩個單獨的JavaScript文件創建2個ID = container1和id = container2的視圖模型。

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

} 

然後將這些2周的ViewModels在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")); 
    } 
}); 

註冊爲獨立的ViewModels篩選後,您可以添加任意數量的視圖模型爲單獨的div。但請確保不要爲註冊div內的div創建單獨的視圖模型。