淘汰赛认购不叫改变观察的数组时
问题描述:
把这个代码:淘汰赛认购不叫改变观察的数组时
var koEvents = new ko.subscribable();
var viewModel = function() {
var self = this;
self.data = ko.observableArray([{
valid: true
}, {
valid: true
}]);
self.isValid = ko.computed(function() {
var isValid = true;
ko.utils.arrayForEach(self.data(), function(item) {
console.log(item.valid);
if (!item.valid) {
isValid = false;
return;
};
});
return isValid;
}, this).subscribe(function(newValue) {
alert("Subscribe called!");
koEvents.notifySubscribers(newValue, "dataChanged");
}.bind(this));
return {
data: self.data,
isValid: self.isValid,
};
}
var vm = new viewModel();
ko.applyBindings(vm, document.getElementById("container"));
vm.data()[0].valid = false;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div data-bind="text: isValid ? 'valid': 'invalid'">
</div>
</div>
我有两个问题...
- 为什么
self.isValid
不叫,当我做这个vm.data()[0].valid = false;
? - 为什么订阅(
alert("Subscribe called!");
)在最初的isValid为true并且以后设置为false时未被调用?我期望在我的代码中调用两次。
感谢
答
有与该代码的几个问题,但相对于你问的主要问题是,在可观察到的排列变换对象上的不可观测性(valid
)是不改变可观察数组,只是它内部对象的一个属性。所以自然没有通知。如果你想要通知,你需要看valid
属性(这意味着它必须是可观察的)。
其他问题:
-
一个与淘汰赛的问题是,它有时解开观测/ computeds你,但如果他们的表达它的一部分不 —你必须这样做(与
()
):<div data-bind="text: isValid() ? 'valid': 'invalid'"></div> <!-- ------------------------^^ -->
你的代码是在试探是否
isValid
(不是isValid()
)是truthy。它始终是,因为它是一个函数参考。仅当标识符不是表达式的一部分时,KO才会为您自动解包。举例来说,这个工程:
<!-- Works --> <div data-bind="visible: isValid">...</div>
但这并不:
<!-- Doesn't work --> <div data-bind="visible: !isValid">...</div>
(当
isValid
是可观察/计算)。 -
您正在将
self.isValid
设置为订阅句柄,而不是计算的,因为您已经过度使用了链接。 :-)你需要完成通话结束后computed
分配,并然后订阅:self.isValid = ko.computed(function() { // ... }, this); // <=== End the assignment here self.isValid.subscribe(function(newValue) { // ... }.bind(this));
您使用
self = this
,但随后也通过this
到computed
使用bind
与subscribe
。这是无害的,但毫无意义。一个或另一个是你需要的。不需要创建一个新的独立对象作为您的虚拟机构造函数的返回值;你已经有一个对象(由
new
创建的对象)。
下面是各种变化的例子。该valid
财产上的第一项设置为false
800毫秒后:
var koEvents = new ko.subscribable();
var viewModel = function() {
this.data = ko.observableArray([{
valid: ko.observable(true)
}, {
valid: ko.observable(true)
}]);
this.isValid = ko.computed(function() {
var isValid = true;
ko.utils.arrayForEach(this.data(), function(item) {
console.log(item.valid());
if (!item.valid()) {
isValid = false;
return;
};
});
return isValid;
}, this);
this.isValid.subscribe(function(newValue) {
alert("Subscribe called!");
koEvents.notifySubscribers(newValue, "dataChanged");
});
}
var vm = new viewModel();
ko.applyBindings(vm, document.getElementById("container"));
setTimeout(function() {
vm.data()[0].valid(false);
}, 800);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div data-bind="text: isValid() ? 'valid' : 'invalid'"></div>
</div>
谢谢! ...以及我被告知要使用Stack Snippets而不是Fiddle ...所以通常我会更新小提琴并在“答案”中提供新的小提琴链接......但是我看不到我如何更新代码没有在这个问题上做? – MojoDK
@MojoDK:你不能。当不可避免的做到这一点时,最好的办法就是在第一句话“我尝试做X回答但它仍然不起作用:”或类似的东西时加上第二个片段。 (然后一旦有必要的答案,你可以再次删除它。)这样做很重要,以限制它已经存在的问题(问题并不意味着移动目标)。在这种情况下,他们是,所以它会没事的。很高兴帮助! –