As the previous answers seem to suggest that AngularJS doesn't provide a targeted solution for your problem, let me propose one using vanilla JS.
AFAIK if you want implement a watcher of an object, you'll need a getter/setter pattern (aka. Mutator method) of some sort. I don't know anything about AngularJS, but I'm quite certain that they must be using something similar as well. There are multiple ways to implement getters and setters in JavaScript (see the Wikipedia page linked above), but in general you have three main choices:
- To use an external handler (an object which hides the internal data structure completely, and only provides an API for reading and writing)
- To use Java-style getSomething and setSomething methods or
- To use native JavaScript property getters and setters introduced in ECMAScript 5.1
For some reason I've seen many more examples of doing it via the first two methods, but on the other hand I've seen one example of a quite complex and beautiful API built with the third method. I'll give you an example of solving your problem via the third method, using Object.defineProperty:
The idea is to provide a watcher function, which is then called as a part of a property setter:
function watcher(objectIndex, attributeName) {
console.log('map[' + objectIndex + '].' + attributeName + ' has changed');
}
Object.defineProperty is a little bit like a complex way to define property for an object. So when you would normally write
obj.val1 = "foo";
you'll write
Object.defineProperty(obj, 'val1', {
get: function () { /* ... */ },
set: function (newValue) { /* ... */ },
// possible other parameters for defineProperty
})
Ie. you define what you want to be done when the obj.val1 is either read and written. This gives you a possibility to also call your watcher function as a part of the setter:
Object.defineProperty(obj, 'val1', {
get: function () { /* ... */ },
set: function (newValue) {
// set the value somewhere; just don't use this.val1
/* call the */ watcher(/* with args, of course */)
}
})
It may seem like it's quite a many lines of code for quite a simple thing, but you can use functional programming techniques and closures to structure your program so that it isn't actually so complicated to write. So in essence even though this may not seem like an "AngularJS-way" of doing things, it isn't actually too much overhead to implement by hand.
Here's a full code example targeting your problem: http://codepen.io/cido/pen/DEpLj/
In the example the watcher function is quite hardly coded to be a part of the data structure implementation. However if you need to re-use this code in multiple places, nothing really stops you from extending the solution with eg. addEventListener-stylish hooks or etc.
As this approach uses closures quite much, it may have some memory implications, if you're really handling massive amounts of data. However, in most use cases you don't have to worry about that kind of things. And on the other hand, all solutions based on "deep equality" checks aren't going to be super memory-efficient or fast ones either.