TL;DR
$onChanges
will not fire just because a bindable object changes. If you need to know every time the object changes, you will have to pass in a new/copied version of the object, or use $doCheck
. Here is a live example on plnkr.co.
The Problem
Imagine we have a data object that gets passed into a child component:
Whenever the color
property changes, we want to run a function. The problem is that the $onChanges
event will not fire because the object itself has not changed.
Three Possible Solutions
1.
In your parent, pass in a copied version of this.data
every time by using angular.copy(this.data)
.
2.
Add the $doCheck
hook to your component which will fire anytime the scope of your component changes. The downside of this approach is that it could be a performance hit.
3.
You can still technically add $scope.$watch
to your $onInit
method, but this is a bad solution. $scope.$watch
is not apart of Angular 2 and relying on it is counter-productive to component-based architecture and any upgrade strategy.
Why $onChanges does not do deep watches
This is by design:
This is indeed intended. It would be too expensive to check each object deeply for changes. Besides, in most cases, where bindings are used in a template, an “internal” change will automatically update the view. If you want to account for “deep” changes, you need to manually $watch the object.