Want to $watch an object in Angular, but ignore changes on certain properties? Here’s a function that will help you out:
function diff(obj1, obj2, exclude) { var r = {}; if (!exclude) exclude = []; for (var prop in obj1) { if (obj1.hasOwnProperty(prop)) { if (exclude.indexOf(obj1[prop]) == -1) { // check if obj2 has prop if (!obj2.hasOwnProperty(prop)) r[prop] = obj1[prop]; // check if prop is object, if so, recursive diff else if (obj1[prop] === Object(obj1[prop])) { if (obj2[prop] == undefined || obj2[prop] == null) r[prop] = obj2[prop]; else { var difference = diff(obj1[prop], obj2[prop]); if (Object.keys(difference).length > 0) r[prop] = difference; } } // check if obj1 and obj2 are equal else if (obj1[prop] !== obj2[prop]) { if (obj1[prop] === undefined) r[prop] = 'undefined'; if (obj1[prop] === null) r[prop] = null; else if (typeof obj1[prop] === 'function') r[prop] = 'function'; else if (typeof obj1[prop] === 'object') r[prop] = 'object'; else r[prop] = obj1[prop]; } } } } return r; }
And here’s how to use it…
$scope.$watch(function () { return vm.objectToWatch; }, function(newValue, oldValue) { var difference = diff(newValue, oldValue, [ newValue.ignoredProp1, newValue.ignoredProp2, newValue.ignoredProp3, newValue.ignoredProp4, ]); // If 'difference' is empty, then return if (Object.keys(difference).length === 0) return; // 'difference' contains properties that we DON't want to ignore so do something... }, true);
And, finally a jsfiddle example.
Just a warning to all, the result of this diff function depends on the order of the arguments. Specifically, I’ve found a scenario where deletion of an array element is not tracked as a difference.
var obj1 = [{ foo: “bar” }];
var obj2 = []
console.log(diff(obj1, obj2)); // {0:{ foo: “bar” }}
console.log(diff(obj2, obj1)); // {}
Interesting. Good find and thanks for the warning.