我正在使用KnockoutJS,我想知道一种方法,observableArray中的可观察对象可以通知父级更改。这是一个例子:
http://jsfiddle.net/paragnair/CEEZ5/
HTML:
<h1 id="heading"> <text data-bind="text:childrenCount"></text> Fields selected</h1>
<table id="form">
<tbody data-bind="foreach:children">
<tr>
<td data-bind="text:name"></td>
<td><input type="checkbox" data-bind="checked:isSelected"/></td>
</tr>
</tbody>
</table>
<a href="#" id="btn-add">Add More Fields</a>
使用Javascript:
var Child = function(name) {
var self = this;
self.name = ko.observable(name);
self.isSelected = ko.observable(false);
},
Parent = function() {
var self = this;
self.children = ko.observableArray([
new Child('One'),
new Child('Two'),
new Child('Three')
]);
self.children.subscribe(function(children) {
header.childrenCount($.map(children, function(a) {
return a.isSelected() ? 1 : null;
}).length);
});
},
header = {
childrenCount: ko.observable(0)
};
var parentModel = new Parent(),
extra = parentModel.children().length;
ko.applyBindings(parentModel, $('#form')[0]);
ko.applyBindings(header, $('#heading')[0]);
function setHeading(childrenCount) {
header.childrenCount(childrenCount);
}
$(document).ready(function() {
$('#btn-add').click(function() {
extra++;
parentModel.children.push(new Child('Extra ' + extra));
return false;
});
});
在上面的示例中,我想显示带有所选字段数的标题。我有subscribe
的{{1}}事件,但只有在数组中添加或删除某些内容时才会触发,因此当用户实际选中字段列表中的复选框时,不会触发该事件。实现此目的的一种方法是在复选框上添加onchange事件以调用父项上的方法,该方法调用一些外部方法来更新observableArray
对象上的childrenCount
。有没有更好的方法呢?
答案 0 :(得分:6)
我认为你可以用不同的方式解决这个问题,同时消除不必要的并发症。您无需将模型分离为单独的applyBindings调用。事实上,除非绝对必要,否则不建议这样做,因为它会增加并发症,如果你不小心可能导致双重绑定。
其次,如果您的标题是您的parentModels子项的结果,那么它确实应该是同一模型的一部分,在编写KO模型时可以而且应该应用OOP原则。这是选择首先使用KO的 优势。
以下是我如何解决您的问题。
http://jsfiddle.net/madcapnmckay/edJyp/
var Child = function(name) {
var self = this;
self.name = ko.observable(name);
self.isSelected = ko.observable(false);
},
Parent = function() {
var self = this;
self.children = ko.observableArray([
new Child('One'),
new Child('Two'),
new Child('Three')
]);
this.childrenCount = ko.computed(function() {
var count = 0;
ko.utils.arrayForEach(self.children(), function (child) {
if (child.isSelected()) {
count++;
}
});
return count;
});
this.addMore = function () {
self.children.push(new Child("Extra " + (self.children().length + 1)));
};
};
var ViewModel = function () {
var self = this;
this.parentModel = new Parent();
};
ko.applyBindings(new ViewModel());
请注意,ViewModel类是多余的,但我假设您有比此处显示的更多功能,这些功能将被标记到此。
顺便说一下,为什么你觉得你需要在按钮上使用jquery点击处理程序?我经常看到这个错误,并想知道文档中的内容会引导你走这条路吗?这也可以并且应该移到你的viewModel上,我在这个例子中已经完成了。
希望这有帮助。
答案 1 :(得分:2)
最后我没有使用订阅,而是使用了event
上的data-bind
,setHeading
依次调用外部函数{{1}}。这是更新的小提琴:http://jsfiddle.net/paragnair/CEEZ5/5/