Is there anyway I can tell the knockout mapping plugin to subscribe to all property changes call a certain function?
I realize I can manually subscribe to the property change event in this manner:
var viewModel = { name: ko.observable('foo'), } // subscribe manually here viewModel.name.subscribe(function(newValue){ // do work })
I would like to be able to generically subscribe though, since my view models may vary, I don't want to hardcode the property names. I created a function that does this, but it may not be the best approach. It works over all browsers except IE7 and below.
Here I take a viewmodel as an argument and try to reflect on it subscribing to the properties:
function subscribeToKO(data) { $.each(data, function (property, value) { if (getType(value) == "Object") data[property] = subscribeToKO(value); else if (getType(value) == "Array") { $.each(value, function (index, item) { item = subscribeToKO(item); }); } else { if (value.subscribe) { value.subscribe(function (newValue) { // do work }); } } }); return data; }
Like I said this works, but since I am using the mapping pluging I was hoping there was a hook I could use to provide it with a function that will generically subscribe to property changes.
Something like:
mapping = { create: function(options){ options.data.subscribe(function(newValue){ // do work ??? }); } } ko.mapping.fromJS(viewModel, mapping);
Any ideas?
Here's a generic approach based on Ryan Niemeyer's dirty flag.
Click here for the JsFiddle.
Html:
<ol> <li> Telephone : <input data-bind="value: telephone"/> </li> <li> Address : <input data-bind="value: address"/> </li> </ol>
Javascript:
var model = { telephone: ko.observable('0294658963'), address: ko.observable('167 New Crest Rd') }; // knockout extension for creating a changed flag (similar to Ryan's dirty flag except it resets itself after every change) ko.changedFlag = function(root) { var result = function() {}; var initialState = ko.observable(ko.toJSON(root)); result.isChanged = ko.dependentObservable(function() { var changed = initialState() !== ko.toJSON(root); if (changed) result.reset(); return changed; }); result.reset = function() { initialState(ko.toJSON(root)); }; return result; }; // add changed flag property to the model model.changedFlag = new ko.changedFlag(model); // subscribe to changes model.changedFlag.isChanged.subscribe(function(isChanged) { if (isChanged) alert("model changed"); }); ko.applyBindings(model);
This handy little plugin is pretty close to what you did but it comes with several options and can work over a much broader set of requirements without requiring the Mapping plugin:
https://github.com/ZiadJ/knockoutjs-reactor
Basically it allows you to write this kind of code:
ko.watch(viewModel, function(target, trigger) { // do work });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With