2011-11-07 95 views
1

讓我們假設我們有一個DOM樹:幾個淘​​汰賽模型綁定樹

<div id="rootNode"> 
    <span data-bind="..." > 

    </span> 

    <div> 
    <div> 
     <span data-bind="..."> </span> 
    </div> 

    <div id="subNode1" > 
     <span data-bind="..." > </span> 
    </div> 
    </div> 
</div> 

所以我們可以綁定模式,那棵樹

ko.applyBindings(model, document.getElementById('rootNode')); 

但是,如果我們想綁定subNode1到其他模型?如果只是寫

ko.applyBindings(model, document.getElementById('subNode1')); 

它不工作我猜是因爲第一次數據綁定重疊第二。

現在我爲什麼要這麼做。我有一個使用Knockout實現的獨立組件的庫。組件是這樣的:

function ComboBox(container) 
{ 
    this.name = new ko.observable(); 
    this.someValue1 = new ko.observable(); 
    this.someValue2 = new ko.observable(); 

    ko.applyBindings(this, document.getElementById(container)); 
} 

不幸的是,我不能寫:

SomeBigComponent('rootNode'); 

ComboBox('subNode'); 

我怎樣才能解決這個問題?第二個問題是以這種方式組織代碼很好嗎?

回答

2

來處理這種情況的典型方法是創建一個是子視圖模型的容器的主視圖模型。

所以,你可以有

var viewModel = { 
    mainModel: { 
    ... 
    }, 
    comboModel: { 
    ... 
    } 
}; 

然後,如果你使用的是1.3測試版,你會做這樣的事情:

<div id="subNode1" data-bind="with: comboModel > 
    <span data-bind="..." > </span> 
</div> 

此前1.3,你會是這樣的:

<div id="subNode1" data-bind="template: { name: 'comboTmpl', data: comboModel }" ></div> 

<script id="comboTmpl" type="text/html"> 
    <span data-bind="..." > </span> 
</script> 

在這兩種情況下,你將能夠調用一次ko.applyBindings整個文檔。

+0

上適當/虛擬網絡API方法,但它是非常不舒服,使其中包含不同基於淘汰賽元素庫,是不是? – Neir0

+0

您只需像控制器一樣使用viewModel並添加/刪除您希望Knockout注意的事物。它們可以是自包含的實體,只是在主視圖模型中添加引用,以便它可用於綁定。否則,你必須將每個模型綁定到不同的元素(而不是彼此的後代)。 –

1

你也可以傳遞一個模式參數到您的視圖模型,並根據設定您用於綁定數據屬性的模式,在您的用戶界面,你會根據mode屬性,使可見其UI才知道,其實這就是一個本身結合

如 - 請在服務器

 <script type="text/javascript" src="../../Scripts/jquery-1.7.1.min.js"></script> 
     <script type="text/javascript" src="../../Scripts/knockout.js"></script> 
     <script type="text/javascript" src="../../Scripts/knockout.mapping-latest.js"></script> 
     <script type="text/javascript"> 
      $(function() { 

       //allows a view to submit info about a new product 
       //and get product data 
       function viewModel(mode) { 
        var self = this; 
        self.mode = mode; 
        if (self.mode == 'i') { 
     self.data = ko.observable(ko.mapping.fromJS({ ProductID: 0, ShortName:[NEW PRODUCT]', SupplierCode: '', UnitsInBox: 0, CostPerUnit: 0, BoxSalePrice: 0, ImageUrl: '', ProductStores: [] })); 
         self.insert = function (callback) { 
          var d = { value: p }; 
          $.ajax({ 
           url: "api/productsapi", 
           type: "POST", 
           data: d, 
           dataType: "json", 
           success: function (d) { 
            self.d.ProductID = d; 
            callback(); 
           }, 
           error: function (e) { 
            alert("error posting"); 
           } 
          }); 
         } 
        } else { 
         self.data = ko.observableArray([]); 
         self.loadAll = function() { 
          $.ajax({ 
           url: "api/productsapi", 
           dataType: "json", 
           data: "{}", 
           type: "GET", 
           success: function (result) { 
            for (var i = 0; i < result.length; i++) { 
             self.data.push(result[i]); 
            } 
           }, 
           error: function (err) { 
            alert("error"); 
           } 
          }); 
         } 
        } 
       }; 

       ko.applyBindings(new viewModel('l')); //change to i for insert 

      }); 
     </script> 

     <div id="newprod" data-bind="visible: mode=='i'"> 
      <span data-bind="text: data().ShortName"></span> 
     </div> 

     <div id="listing" data-bind="visible: mode=='l'"> 
      <span data-bind="text: data().length"></span> 
      <button data-bind="click: loadAll">Load</button> 
     </div>