1
votes

I've got a Knockout application with a hierarchy of objects. If I want to access a deep level in an object in an HTML tag, I'd use something like:

data-bind="text: property1().property2().property3()"

I want to subscribe to the same target in pure Javascript i.e. execute a function whenever property3 changes on the currently bound object, or whenever the hierarchy changes below property3. In other words I'd like to do something like:

myviewmodel.deepSubscribe("property1().property2().property3()", function() { .... });

How do I go about this in knockout?

3

3 Answers

5
votes

It's better to use computed feature of knockout.

You can declare:

var computedProp = ko.computed(function(){
    return property1().property2().property3();
}

Then you can bind like:

data-bind="text: computedProp"

And you can subscribe to it like:

computedProp.subscribe(function() { .... });
2
votes

For this I wrote Knockout Reactor here:

https://github.com/ZiadJ/knockoutjs-reactor

It does a good job at subscribing deeply to hierarchical models and provides a lot of flexibility.

2
votes

In the simplest case you'd just subscribe directly to property3. Suppose a view model like this:

var reality = {
    dreamLevel1: ko.observable({
        dreamLevel2: ko.observable({
            dreamLevel3: ko.observable("some value")
        })
    })
};

You could then subscribe some plain javascript to changes in property3 like this:

reality.dreamLevel1().dreamLevel2().dreamLevel3.subscribe(function(newVal) {
    document.getElementById('proofOfConcept').innerHTML += "\n" + newVal
});

See this fiddle for a demo of what I mean.

Of course, you'd need to re-subscribe if property2 or property1 changes. You could factor out the code you want to execute on a subscription:

function lvl3Subscription(newVal) {
    document.getElementById('proofOfConcept').innerHTML += "\n" + newVal
}

Then directly subscribe this for the initial level 3 property:

reality.dreamLevel1().dreamLevel2().dreamLevel3.subscribe(lvl3Subscription);

as well as the level 2 property:

reality.dreamLevel1().dreamLevel2.subscribe(function(newDream) {
    newDream.dreamLevel3.subscribe(lvl3Subscription); 
});

and so on. Now if level 2 gets changed and consequently level 3 becomes totally different the custom Javascript code will still be subscribed to on the new level 3 observable.

See this in action in the updated fiddle.