32

I have a viewmodel which contains an observable, which is initialized with an object. this object itself contains observables.

my goal is to be notified whenever that object changes (or: when any observable in that object changes)

jsfiddle

complex object:

var ns = ns || {}; ns.ComplexObj = function (item) { var self = this; if (!item) { item = {}; } self.id = item.Id || ''; self.company = ko.observable(item.Company || ''); self.email = ko.observable(item.Email || ''); self.company.subscribe(function () { console.log('debug: company changed'); }); return self; }; 

viewmodel

ns.mainvm = function () { var simpleObject = ko.observable('i am pretty simple'); simpleObject.subscribe(function (newValue) { document.getElementById('simpleSubscribtionFeedback').innerText = newValue; }); var complexObject = ko.observable(ns.ComplexObj()); complexObject.subscribe(function (newValue) { // i would like to react to any change in complex object document.getElementById('complexSubscribtionFeedback').innerText = 'i dont get executed :('; }); return { simpleObject: simpleObject, complexObject: complexObject }; }; 

binding

var container = document.getElementById('wrapper'); if (container) { ko.applyBindings(ns.mainvm, container); } else { console.warn("container for binding ko not found"); } 

is there any possiblity to react on changes on a complex object? any help is appreciated.

i already tried the dirtyFlag solutions (link in the comments), from rpniemeyer. the problem with a dirty flag on the complex object is, that when it switches to "true" and i'm hooking into the subscription of that flag, thats only ok for the first time. to react to further changes, i would need to set the dirtyFlag to false again (after doing my stuff in the subscription). which would lead into a subscription loop.

2

1 Answer 1

61

You can use the following trick:

ko.computed(function() { return ko.toJSON(complexObject); }).subscribe(function() { // called whenever any of the properties of complexObject changes }); 

See http://jsfiddle.net/xcajt4qn/3/

The reason why this works is ko.toJSON will recursively read all the properties in the object, therefore making the computed depend on all the properties.

Sign up to request clarification or add additional context in comments.

4 Comments

Note that this will also be called whenever any of the object's non-observable properties change, which may not be desired.
@tloflin how so? there wouldn't be any change tracking on those properties
Tip : Put a console.log in the subscribe to check it isn't being called too many times. You can use a rate limiting observable to avoid too many events which is especially useful if the fields are text inputs. Add extend({ rateLimit: 500 }) before the subscribe function for that case. I believe rateLimit: 0 or extend({ deferred: true }); may be useful if you find you are getting multiple events raised for each change.
Is there a simple way to identify which property raised the change event?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.