2016-02-27 154 views
0

我有以下部件不更新數據有不同的屬性:淘汰賽組件

function Fruit(data) { 
    this.name = ko.observable(data.name); 
    this.color = ko.observable(data.color); 
} 
function Dessert(data) { 
    this.name = ko.observable(data.name); 
    this.packaging = ko.observable(data.packaging); 
} 
function Vm(){ 
    var data = [{name:"Apples",color:"Yellow"},{name:"Cookies",packaging:"Box"}]; 
    this.items = ko.observableArray([new Fruit(data[0]),new Dessert(data[1])]); 
    this.items.choice = ko.observable(this.items()[0]); 
} 

這部分工作得很好,每一次我改變文字在我的輸入框時的基礎數據更新:

<div data-bind="component: {name: 'fruits', params: items.choice}"></div> 

現在,我想我的觀測的邏輯封裝成組件本身,所以我改變了組件是這樣的:

ko.components.register('fruits', { 
    viewModel: function(params) { 
     this.name = ko.observable(params.name); 
     this.color = ko.observable(params.color); 
    }, 
    template: { element: 'fruits-tpl' } 
}); 

...現在我有我的觀察到items.choice只只內部數據:

function Vm(){ 
    var data = [{name:"Apples",color:"Yellow"},{name:"Cookies",packaging:"Box"}]; 
    this.items = ko.observableArray(data); 
    this.items.choice = ko.observable(this.items()[0]); 
} 

爲什麼雲在主視圖模型的基礎數據沒有更新我的第二個例子,雖然items.choice仍然是觀察到的?我確信我錯過了一些概念,也許我可觀察數組中的每個項目都應該是可觀察的,但是我不明白是否有辦法讓第二個例子工作。

第一個例子:http://jsfiddle.net/5739ht0q/2/ 第二個例子:http://jsfiddle.net/079tx0nn/

+1

你創建你的組件內部觀測。他們正在更新。您打印的是傳遞到組件的數據,並且不會更新。你不能看從你的組件內部創建的數據 –

+0

是的,有沒有辦法將數據更新回項目數組? – deblocker

回答

1

有幾種方法可以將數據更新回主視圖模型。

讓我們精煉只是一點點的主視圖模型:

function Vm(data) { 
    var self = this; 
    self.items = ko.observableArray(ko.utils.arrayMap(data, function(item) { 
    return ko.observable(item); 
    })); 
    self.items.choice = ko.observable(0); 
    self.items.choice.data = ko.computed(function() { 
    return self.items()[self.items.choice()]; 
    }); 
} 

1)第一快速&骯髒的方式是通過該組件已在主視圖模型中定義的函數:

<div data-bind="component: { 
    name: 'fruits', 
    params: {index: items.choice(), data: items.choice.data(), update: items.update} 
}"></div> 

組件內部,我們可以調用函數保存更改:

self.data = ko.computed(function(){ 
    params.update(params.index, ko.toJS(self)); 
}); 

主視圖模型中的更新功能現在很明顯,不需要花費更多關於該功能的文字。

2)的第二種方法是使用一個可訂閱以建立沿着視圖模型的通信:

ko.intramodels = new ko.subscribable(); 

從組件,發送通知:

self.data = ko.computed(function(){ 
    ko.intramodels.notifySubscribers(ko.toJS(self), "updateFruits"); 
}); 

內的訂閱主視圖模型將接收並保存更改,或多或少如下所示:

ko.intramodels.subscribe(function(newValue) { 
    self.items.replace(self.items()[self.items().index], newValue); 
    }, self, "updateFruits"); 

當然這可以像上面那樣手工完成,但是偉大的Ryan Niemeyer的郵箱圖書館將是這裏的最佳選擇:https://github.com/rniemeyer/knockout-postbox

我測試了兩種解決方案,但不幸的是,當我激活 - 新的淘汰賽3.4 - 延期更新選項:ko.options.deferUpdates = true;,因爲我收到「最大調用堆棧大小超出」錯誤時遇到了一些麻煩。

3)最終的解決方案:因爲我不想放棄和錯過淘汰賽3.4的這個新的精彩的性能增強,同時由於這個錯誤也意味着或多或少:「循環依賴是一個設計錯誤,請重新思考你實現」的某些部分,我改變視圖模型,以保持依賴跟蹤鏈只能在一個方向努力,但只用一個可觀察整個組件的數據:

ko.components.register('fruits', { 
    viewModel: function(params) { 
    var self = this; 
    self.data = params.peek(); 
    self.item = {}; 
    self.item.name = ko.observable(self.data.name); 
    self.item.color = ko.observable(self.data.color); 
    self.update = ko.computed(function() { 
     params(ko.toJS(self.item)); 
    }); 
    }, 
    template: { 
    element: 'fruits-tpl' 
    } 
}); 

這是迄今爲止更嵌套組件具有所有數據處理和obs在其中ervable創建,主視圖模型簡化版,必須瞭解什麼是孩子,爲什麼裏面任何東西 - 僅僅只傳遞和接收回一個觀察的對象:

<div data-bind="component:{name:'fruits',params:items.choice.data}"></div> 

<template id="containers-tpl"> 
    <div data-bind="foreach: containers"> 
    <p><input data-bind="textInput: quantity"><span data-bind="text: name"></span></p> 
    </div> 
</template> 

<template id="fruits-tpl"> 
    <p>Name:<input data-bind="textInput: item.name"></p> 
    <p>Color:<input data-bind="textInput: item.color"></p> 
    <div data-bind="component:{name:'containers',params:item.containers}"</div> 
</template> 

關鍵點這裏:將組件的可見性傳遞給組件,而不僅僅是數據,並在組件內打破參數的依賴關係鏈。

完全撥弄嵌套組件:http://jsfiddle.net/jo37q7uL/

0

觀測量是在敲除的心臟,並允許2路視圖和視圖模型之間的結合。對於要更新組件的JSON字段,需要更改'VM'有權訪問的可觀察值。

爲了避免定義水果和甜品功能,您可以使用Knockout mapping將您的數據陣列轉換爲ko.observableArray。這會將數組中每個對象的字段設置爲可觀察對象,以便將它們傳遞給組件綁定。

+0

,這與我的第一個示例中的相同,每個數組項的每個屬性從一開始就已經是可觀察的,只是在映射插件的幫助下完成的。這就是我所要求的,如果有可能避免這種情況。 – deblocker