Hooking into the component's life cycle

Components in Angular have a well-defined life cycle, which allows us to hook into different phases of it and have further control over our application. We can do this by implementing specific methods in the component's controller. In order to be more explicit, thanks to the expressiveness of TypeScript, we can implement different interfaces associated with the life cycle's phases. Each of these interfaces has a single method, which is associated with the phase itself.

Although code written with explicit interface implementation will have better semantics, since Angular supports ES5 as well, within the component we can simply define methods with the same names as the life cycle hooks (but this time, prefixed with ng) and take advantage of duck typing.

The following diagram shows all the phases we can hook into:

Hooking into the component's life cycle

Figure 10

Let's take a look at the different life cycle hooks:

  • OnChanges: This hook will be invoked once a change in the input properties of a given component is detected. For instance, let's take a look at the following component:
      @Component({ 
        selector: 'panel', 
        inputs: ['title'] 
      }) 
      class Panel {...} 

We can use it like this:

<panel [title]="expression"></panel> 

Once the value of the expression associated with the [title] attribute is changed, the ngOnChanges hook will be invoked. We can implement it using this code snippet:

@Component(...) 
class Panel { 
  ngOnChanges(changes) { 
    Object.keys(changes).forEach(prop => { 
      console.log(prop, 'changed. Previous value', changes[prop].previousValue); 
    }); 
  } 
} 

The preceding snippet will display all the changed bindings and their old values. In order to be more explicit in the implementation of the hook, we can use interfaces:

import {Component, OnChanges} from '@angular/core'; 
@Component(...) 
class Panel implements OnChanges { 
  ngOnChanges(changes) {...} 
} 

All the interfaces representing the individual life cycle hooks declare a single method with the name of the interface itself prefixed with ng. In the upcoming list, we'll use the term life cycle hook, both for interface and/or the method, except if we won't imply anything specifically for only one of them.

  • OnInit: This hook will be invoked once the given component is initialized. We can implement it using the OnInit interface with its ngOnInit method.
  • DoCheck: This will be invoked when the change detector of the given component is invoked. It allows us to implement our own change detection algorithm for the given component. Note that DoCheck and OnChanges should not be implemented together on the same directive.
  • OnDestroy: If we implement the OnDestroy interface with its ngOnDestroy method, we can hook into the destroy life cycle phase of a component. This method will be invoked once the component is detached from the component tree.

Now, let's take a look at the life cycle hooks associated with the component's content and view children:

  • AfterContentInit: If we implement the ngAfterContentInit life cycle hook, we will be notified when the component's content is fully initialized. This is the phase when the properties decorated with ContentChild or ContentChildren will be initialized.
  • AfterContentChecked: By implementing this hook, we'll be notified each time the content of the given component has been checked by the change detection mechanism of Angular.
  • AfterViewInit: If we implement this life cycle hook with its ngAfterViewInit method, we will be notified when the component's view is initialized. This is the phase when the properties decorated with ViewChild or ViewChildren will be initialized.
  • AfterViewChecked: This is similar to AfterContentChecked. The AfterViewChecked hook will be invoked once the view of our component is checked.

Order of execution of the life cycle hooks

In order to trace the order of execution of the callbacks associated with each hook, let's take a peek at the ch4/ts/life-cycle/app.ts example:

@Component({ 
  selector: 'panel', 
  template: '<ng-content></ng-content>' 
}) 
class Panel { 
  @Input() title: string;
  @Input() caption: string;
  ngOnChanges(changes) {...} 
  ngOnInit() {...} 
  ngDoCheck() {...} 
  ngOnDestroy() {...} 
  ngAfterContentInit() {...} 
  ngAfterContentChecked() {...} 
  ngAfterViewInit() {...} 
  ngAfterViewChecked() {...} 
} 

The Panel component implements all the hooks without explicitly implementing the interfaces associated with them.

We can use the component in the following template:

<button (click)="toggle()">Toggle</button> 
<div *ngIf="counter % 2 == 0"> 
  <panel caption="Sample caption" >Hello world!</panel> 
</div> 

In the preceding example, we have a panel and a button. Upon each click of the button, the panel will be either removed or appended to the view by the ngIf directive.

During the application initialization, if the result of the "counter % 2 == 0" expression is evaluated to true, the ngOnChanges method will be invoked. This happens because the values of the title and caption properties will be set for the first time.

Right after this, the ngOnInit method will be called, since the component has been initialized. Once the component's initialization is completed, the change detection will be triggered, which will lead to the invocation of the ngDoCheck method that allows us to hook custom logic for detecting changes in the state.

Note

Note that you are not supposed to implement both ngDoCheck and ngOnChanges methods for the same component, since ngOnChanges will keep being called when the internal change detector detects changes. The example here does this for learning purposes only.

After the ngDoCheck method, the change detector will perform a check on the component's content (ngAfterContentInit and ngAfterContentChecked will be invoked in this order). Right after this, the same will happen for the component's view (ngAfterViewInit followed by ngAfterViewChecked).

Once the expression of the ngIf directive is evaluated to false, the entire component will be detached from the view, which will lead to the invocation of the ngOnDestroy hook.

On the next click, if the value of the expression of ngIf is equal to true, the same sequence of calls of the life cycle hooks as the one during the initialization phase will be executed.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset