Friday, July 22, 2016

Component Lifecycle: $doCheck (angular 1.5.x)

Since angular 1.5 components got introduced together with a well defined lifecycle. Currently their are 4 hooks you can use in angular 1 components:

  • $onInit
  • $onChanges
  • $postLink
  • $onDestroy

$doCheck

In version 1.5.8 a new hook is introduced: $doCheck. And this is the equivalent of the angular 2 ngDoCheck implementation. It also serves the same purpose as the $onChanges, allow to act on changes made to the bindable fields of a component. As $onChanges uses the built-in change detection of angular, the $doCheck implementation is totally up to you. The hook is called for every digest cycle of the component and just let’s you know you should check your bindings on changes so you can act on it.

Usage

One of the case this could be useful is when you make use of the one-way (<) binding for passing objects. In this case the $onChanges hook will be called if the reference of the object changes and not when fields on the object it self change. So currently you had 2 possibilities to solve this:

  1. Always make sure you are passing a new object. This way $onChanges hook will be called for every change because the reference of the object will change from time to time.
  2. Add a watch on the object to keep track of the changes. This also means you need to destroy and recreate the the watch every the reference of the object changes and you have an (unwanted) dependency on $scope inside your component.
   1: module.component("component",{
   2:     template: "<div>{{$ctrl.item}}</div>",
   3:     bindings: {
   4:         inputItem: "<item"
   5:     },
   6:     controller: ["$scope", function($scope){
   7:         var $ctrl = this;
   8:         var destroyWatch;
   9:         this.$onChanges = function(changeObj){
  10:             if(changeObj.inputItem){
  11:                 this.item = 
  12:                   angular.copy(changeObj.inputItem.currentValue);
  13:                 if(destroyWatch) destroyWatch();
  14:                 destroyWatch = $scope.watch(function (){ 
  15:                     return changeObj.inputItem.currentValue 
  16:                 }, function (){ /* handle Changes */ })
  17:             }
  18:         }
  19:     }
  20: }]);

The $doCheck hook now adds a third possibility to solve this issue. By checking manually if the object has changed you can act on it. This can be done by storing the passed value into a local variable, so it can be used in the next call as previous value for comparison.

   1: module.component("component",{
   2:     template: "<div>{{$ctrl.item}}</div>",
   3:     bindings: {
   4:         inputItem: "<item"
   5:     },
   6:     controller: function(){
   7:         var $ctrl = this;
   8:         var previousInputItem;
   9:         this.$doCheck = function(){
  10:             if(!angular.equals(previousInputItem, this.inputItem)){
  11:                 previousInputItem = this.inputItem;
  12:                 this.item = angular.copy(this.inputItem);
  13:             }
  14:         }
  15:     }
  16: });

Performance

Change detection in angular 1.x is done using digest cycles and for every cycle the $doCheck hook will be called. This means this will be called a lot. This is why you have the be careful using this hook so it doesn’t cause any performance issues. Also keep in mind that any change made to the model inside the $doCheck hook will trigger a new digest cycle. If implemented wrong this can result into a loop of digest cycles.

In angular 2 the change is implemented on a different (more performant) way and this will result in less calls of the ngDoCheck. It will also throw an error if you trigger changes outside of the component in prod mode.

Conclusion

The $doCheck hook gives you the ability to take the change detection of the bindable fields into your own hands. This makes it possible to detect changes inside objects and arrays without having to change the reference. Ditto for detecting changes in date objects.

The $onChanges and $doCheck hook can easily live side-by-side. The $doCheck hook doesn’t effect the $onChanges hook at all. Of course fields checked in the $doCheck hook no longer need to be handled in the $onChanges hook. In angular 2 it’s even recommended to not use these 2 hooks together.

15 comments:

  1. Great and really helpful article! Adding to the conversation, providing more information, or expressing a new point of view...Nice information and updates. Really i like it and everyday am visiting your site..

    CRO Agency in Chennai

    ReplyDelete
  2. This comment has been removed by a blog administrator.

    ReplyDelete
  3. This comment has been removed by a blog administrator.

    ReplyDelete
  4. Nice to know this for binding changes but this bring me a question: In Angular 1.5 component, what's the correct way to implement a resize event so that we detect component width change? Any suggestion?

    ReplyDelete
  5. Hi, Got a question on your statement: "The hook is called for every digest cycle of the component" of when this doCheck actually gets executed.

    Does that mean it is isolated to just the bindings changes of the component?

    or the main $digest loop, ie any thing on the angular app that would fire off the $digest loop?

    ReplyDelete
  6. Wow! Thanks for this valuable information about new programming tools. It is not everyday that I have a possibility to see something like this. I like the way you write and presenting your ideas and views. I am hoping the same coolant works from you in future. Do not hesitate to use www.custom-paper-writing.org help for all new posts and be sure in their brilliant quality 24/7! You will be satisfied with the result.

    ReplyDelete
  7. Thank you for this article, I m looking this because I wanted to pass the same object between components changing only properties or methods while $onChanges hook is activated.

    ReplyDelete
  8. In this case, "$ctrl = this" is not necessary, right?

    ReplyDelete
  9. Just wish to say your article is as astounding. The clearness in your
    submit is just excellent and i can suppose you’re knowledgeable in this subject.
    Well along with your permission allow me to take hold of your RSS feed to stay up
    to date with drawing close post. Thanks a million and
    please carry on the rewarding work.
    Check Mine: AngularJS Training in Chennai

    ReplyDelete
  10. I found this blog very useful. I also recommend you visit this page to know how to spy on facebook.

    ReplyDelete
  11. I really to read your blog.You provide valuable information in this blog.This information can help lot of fresher to learn Angularjs. Thanks for sharing.keep sharing more blogs.


    Angularjs Online Training

    ReplyDelete
  12. This comment has been removed by the author.

    ReplyDelete
  13. Good Explanation for Component Lifecycle$doCheck (angular 1.5.x), Please give some example in AngularJs 4, I want to Learn AngularJs 4

    ReplyDelete