Knockout js subscribe function (for an observable) is being executed inside ko.applyBindings(...)

Zahra picture Zahra · Dec 13, 2013 · Viewed 41.5k times · Source

I have got a subscribe function on one of my observable objects. I assume that the subscribe function should only execute when there is a change to it's observable object. Though when I trace my code, I can see that it's being executed after I call the ko.applyBindings(MyViewModel); at initialization.

Here is what I have got in my viewmodel:

function MyViewModel(myModel){
    this.myProperty = ko.observable(myModel.myProperty);

    this.myProperty .subscribe(function (val) {
        // do sth..
    }, this);
}

and this is where I make the call to applyBindings:

jQuery(document).ready(
    function ($) {
       ko.applyBindings(MyViewModel);
});

Is this an expected behavior?

The subscribe function is being called right after ko.applyBindings(MyViewModel);, meaning that I don't get any input from the UI in the meanwhile.

I would want to have it so it only executes my subscribe function body whenever the value of myProperty is changed. Is there a way for me to track my observable object to see where is the change happening?

Answer

Josh Taylor picture Josh Taylor · Dec 13, 2013

When you set up a subscription, the subscription is evaluated and triggered when you call ko.applyBindings().

If you are only looking at change tracking, you could use a computed observable and achieve the same result. It looks like you can defer the computed observable from being evaluated on ko.applyBindings() by adding the {deferEvaluation: true} option shown below:

For example:

    function MyViewModel(myModel){
        this.myProperty = ko.observable('someValue');
        this.runCode = ko.computed(function (val) {
            // do some stuff any time this.myProperty() is changed
            console.log(this.myProperty());
        }, this, {deferEvaluation: true});
    }

var vm = new MyViewModel();

ko.applyBindings(vm);

vm.runCode();

vm.myProperty('some new value2');

This will prevent the default behavior of having the code executed as it is evaluated. In order to have it start tracking events you have to call the computed (vm.runCode() in this case) when you want it to start tracking.

Heres the updated fiddle that shows the behavior: http://jsfiddle.net/amspianist/SL22M/2/