Force a computed property function to run

George Mauer picture George Mauer · Dec 7, 2012 · Viewed 43.4k times · Source

Given a computed property

vm.checkedValueCount = ko.computed(function(){
  var observables = getCurrentValues();  //an array of ko.observable[]
  return _.filter(observables, function(v) { return v() }).length;
});

suppose getCurrentValues() can return different sets of observables which are modified elsewhere in the code (and comes from a more complex structure than an observableArray).

I need checkedValueCount to update whenever

  • one of its dependencies change
  • getCurrentValues() returns a different set of observables.

The problem is that ko.computed seems to memoize the last returned value and only update when a dependency updates. This handles the first case but not the latter.

What I'm looking for is a way to force checkedValueCount to re-run. Something which I can use like:

changeCurrentValues();
vm.checkeValueCount.recalculate();

Put most simply, given that I have

a = ko.computed(function() { return Math.random() })

how can I force invoking a() twice to return different values.

Answer

Josh picture Josh · Dec 7, 2012

I realized my first answer missed your point, and won't solve your issue.

The problem is that a computed will only reevaluate if there is some observable that forces it to re-evaluate. There is no native way to force a computed to re-evaluate.

However, you can get around this with some hackery by creating a dummy observable value and then telling its subscribers that it has changed.

(function() {

    var vm = function() {
        var $this = this;

        $this.dummy = ko.observable();

        $this.curDate = ko.computed(function() {
            $this.dummy();
            return new Date();
        });

        $this.recalcCurDate = function() {
            $this.dummy.notifySubscribers();
        };        
    };

    ko.applyBindings(new vm());

}());​

Here is a Fiddle showing this approach