拿这段代码:
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;
? - 为什么当 isValid 最初为 true 后来设置为 false 时不调用 subscribe (
alert("Subscribe called!");
)?我希望它在我的代码中被调用两次。
谢谢
最佳答案
该代码有几个问题,但与您所问的内容相关的主要问题是更改可观察数组中对象的不可观察属性(有效
)不是更改可观察数组,只是其中对象的一个属性。所以自然没有通知。如果你想要通知,你需要观察 valid
属性(这反过来意味着它必须是可观察的)。
其他问题:
Knockout 的一个问题是它有时会为您解包 observables/computeds,但如果它们是表达式的一部分,它不会 — 你必须这样做(使用
()
):<div data-bind="text: isValid() ? 'valid': 'invalid'"></div> <!-- ------------------------^^ -->
您的代码正在测试
isValid
(不是isValid()
)是否为真。它始终是,因为它是一个函数引用。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
。这是无害的,但毫无意义。一个或另一个就是您所需要的。无需创建新的单独对象作为 VM 构造函数的返回值;您已经有一个对象(由
new
创建的对象)。
这是一个包含这些不同变化的示例。第一个条目的 valid
属性在 800 毫秒后设置为 false
:
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>
关于javascript - 更改可观察数组时不调用 knockout 订阅,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45502475/