Reputation: 33
I have a computed observable that does not update due to the order of the observables in the computed observable function. Clicking on the branch does not update the computed observable on the leaf. Is this intended?
https://jsfiddle.net/acL3f1qp/9/
javascript:
(function() {
function Branch(viewModel) {
var self = this;
self.isAllowed;
self.isChecked = ko.observable();
self.isChecked.subscribe(function(newValue){
//is updating?
null;
});
self.leaves = [];
self.allowLeaves = ko.computed(function() {
return viewModel.allowLeaves() && (!self.isAllowed || self.isChecked());
});
}
function Leaf(branch) {
var self = this;
var isCheckedInternal = ko.observable();
self.isAllowed;
self.isChecked = ko.computed({
read: function() {
return branch.allowLeaves() && isCheckedInternal();
},
write: function(value) {
isCheckedInternal(value);
}
});
}
function ViewModel() {
var self = this;
var branch;
var leaf;
self.allowLeaves = ko.observable(true);
self.branches = [];
branch = new Branch(self);
branch.isAllowed = true;
branch.isChecked(true);
leaf = new Leaf(branch);
leaf.isAllowed = true;
leaf.isChecked(true);
branch.leaves.push(leaf);
self.branches.push(branch);
}
ko.applyBindings(new ViewModel());
})();
html:
<div>
<label>
<input type="checkbox" data-bind="checked: allowLeaves" />
<span>allow leaves</span>
</label>
</div>
<div class="indent" data-bind="foreach: branches">
<div>
<label>
<input type="checkbox" data-bind="checked: isChecked, visible: isAllowed" />
<span>branch</span>
</label>
</div>
<div class="indent" data-bind="foreach: leaves">
<div>
<label>
<input type="checkbox" data-bind="checked: isChecked, visible: isAllowed" />
<span>leaf</span>
</label>
</div>
</div>
</div>
<br />
clicking on "branch" does
not update computed on leaf!
Upvotes: 3
Views: 506
Reputation: 1123
The order of observables in a computed only matters as far as building dependencies;
In this computed:
ko.pureComputed(function(){
return a() && b();
}
(assume a
and b
are observable and return either true
or false
)
If a returns false then b
will not be evaluated (since the && operator is lazy) and KO will not create a dependency on b
, only on a
.
This is good - any change to b
can have no impact on the value of this computed so reevaluating would be a waste of resources.
If a
is updated to return true
KO will reevaluate the computed (since it does have a dependency on a
) and in doing so will need to find out what value b
has and will then create a dependency.
As for your fiddle - as far I can see your problem is that the isChecked
observable on the branch is not linked in any way to the allowLeaves
computed. So it doesn't get updated.
If you change you implementation of Branch
to look more like Leaf
with an isCheckedInternal
like this:
function Branch(viewModel) {
var self = this;
self.isAllowed = ko.observable();
var isCheckedInternal = ko.observable();
self.leaves = [];
self.allowLeaves = ko.pureComputed({
read: function() {
return viewModel.allowLeaves() && isCheckedInternal();
},
write: function(val){
isCheckedInternal(val);
}});
}
and then bind the checked to allowLeaves
then it appears to work as expected.
I have a fiddle which is working...
Upvotes: 2