MikeW MikeW - 1 month ago 13
AngularJS Question

watch depth and content of complex object hierarchy in angular

I am trying to write some code to detect changes to a complex nested, hierarchical object in angular. I was hoping that a

$watch
or
$watchCollection
expression would suffice, however this is proving difficult to achieve.

Could someone suggest a good approach to the problem?

an example of the data structure I am looking to watch is (in json):

{
"$type":"<>f__AnonymousType7`2[[System.String, mscorlib],[System.Object, mscorlib]], VM.ConfigurationServer",
"Name":"DevelopmentEnvironment",
"Descendents":{
"$type":"<>f__AnonymousType7`2[[System.String, mscorlib],[System.Object, mscorlib]][], VM.ConfigurationServer",
"$values":[{
"$type":"<>f__AnonymousType7`2[[System.String, mscorlib],[System.Object, mscorlib]], VM.ConfigurationServer",
"Name":"MoreSpecificEnvironment",
"Descendents":{
"$type":"<>f__AnonymousType7`2[[System.String, mscorlib],[System.Object, mscorlib]][], VM.ConfigurationServer",
"$values":[{
"$type":"<>f__AnonymousType7`2[[System.String, mscorlib],[System.Object, mscorlib]], VM.ConfigurationServer",
"Name":"level3",
"Descendents":null
}]
}
}]
}
}


as you can see the TypeNameHandling of the Json Serializer is set to All, that is necessary for other parts of the system.

What I need to be made aware of is any changes to the
Name
property on any of the nested objects, and also addition or removal of a
Descendent
.

I have tried both

scope.$watch(<objectname>, function(){...}, true);
and

scope.watchCollection(<objectname>, function(){...}, true);


both of which detect changes to the Top level
Name
and
Descendents
properties but nothing on objects nested further.

Based on my understanding, this suggests to me that the
angular.equals
function is not noticing the changes below the top level.

Is there a way to inject a custom equality comparer?

Is there a way to change the
watchExpression
dynamically? Thus applying a watch to every object in the hierarchy, and as the hierarchy changes changing the
watchExpression

Answer

The issue is that angular.equals() ignores keys starting with a $ sign, i.e. in your case $type and $values are ignored during comparison.

Do not use properties starting with $ signs in your Angular code apart from Angulars own services / directives / etc.!

Check out this fiddle and try renaming the $values array to just values.