3
votes

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?

2
the subscription will only run when the value changes. It is possible for the value to change during applyBindings from a binding that writes to its value. Do you happen to have your property bound in a select using the value binding and have an initial numeric value that is getting updated to be a string? - RP Niemeyer
@RPNiemeyer: Thanks for your helpful comment. The subscribe was actually being called after the initialization due to some changes coming from the back-end code. - Zahra

2 Answers

5
votes

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/

2
votes

Are you referencing the object in your binding like this?

<div data-bind="text: myProperty()"></div>

as opposed to:

<div data-bind="text: myProperty"></div>

That might give you the issues you are talking about as the function is being called in the binding.