2016-02-27 160 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