knockout.jsknockout-3.0computed-observable

Computed stops triggering forever if dependency is inside of false branch statement


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...


Solution

  • 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:

    updateComputed = ko.pureComputed(function () {
        updateTrigger();
        result(evaluator.call(owner));
    });
    ko.computed(function () {
        var isActive = result.active();
        if (isActive && !updateSubscription) {
            updateSubscription = updateComputed.subscribe(function () {}); 
        } else if (updateSubscription && !isActive) {
            updateSubscription.dispose();
            updateSubscription = undefined;
        }
    });
    

    https://jsfiddle.net/mbest/bpr88bp3/2/