I'm faced a problem that my computed observable stops triggering after some sequence of dependency changes. Finally I found out the point: if dependency was inside of false branch statement during latest evaluation, computed will not be triggered next time even if condition became true before evaluation finished. Here is a sample: https://jsfiddle.net/sgs218w0/1/
var viewModel = new function(){
var self = this;
self.trigger = ko.observable(true);
self.fire = function(){
self.trigger(! self.trigger());
};
self.content = function(){
var test = 3;
return ko.computed(function(){
alert("triggered!");
if(test !== 0){
console.log(self.trigger());
alert(test);
}
test--;
});
}();
};
ko.applyBindings(viewModel);
Is it bug or feature? Do you know any workaround for this issue? I seems to be optimization, but it looks aggressive and incorrect for me. (Edit: I changed my mind. It is reasonable, but can lead to some issues sometimes. I think knockout should have options to fix this issues)
P.S. I could publish more detailed example of real code to make question more specific, if you need it. But the point of real code it the same.
UPDATE Well, I had to be less lazy to provide more detailed example of what I want achieve. I like the idea of computed which automatically make ajax calls. Described here. One disadventure I see is that call will be made even if corresponding part of UI is invisible. I tried to fix it this way: https://jsfiddle.net/bpr88bp3/1/. The problem is that once tab is deativated it can't be activated anymore, because computed stops triggering...
The idea, in general, is that all dependencies of a computed observable should also be observables. In your case,
test
isn't an observable; if you make it observable, your code should work as expected:But this introduces another problem because you're now changing one of the dependencies within your computed observable. By changing
test
, logically, the computed should be evaluated recursively. If the computed is synchronous, Knockout prevents this, but this is not really a feature, and it could cause problems later.Here's what I think is a better solution that properly isolates the meanings of the components:
After reading the update to your question and looking through the updated example code, I've come up with a real solution. This uses a
pureComputed
to do the update, taking advantage of the fact that a pure computed can be activated and deactivated by subscribing to it and disposing the subscription. Here is the important code:https://jsfiddle.net/mbest/bpr88bp3/2/
According to the Knockout JS documentation:
When
if(test !== 0){
is false, Knockout does not subscribe toself.trigger()
due toself.trigger()
not being called during computed recalculation. With no subscription to theself.trigger()
, there is no recalculation of the computed on furtherself.trigger()
changes.IMHO the workaround is to get
self.trigger()
in any case (updated fiddle):