A guide to lifecycle hooks in Angular

Introduction

Learn about all the hooks available for use in your Angular workflow for building awesome applications.

Angular

Angular is a TypeScript framework for building web applications, mobile or desktop with over 49,000 stars on GitHub. Maintained by the Angular team at Google and a host of community members and organizations, it combines declarative templates, dependency injection, end to end tooling, and integrated best practices to solve development challenges. Angular empowers developers to build applications that live on the web, mobile, or the desktop. It has a very useful CLI tool for beginners to easily get started, there is even a GUI client called Console.

Prerequisites

To be able to follow through in this article's demonstration you should have:

  • Node version 11.0 installed on your machine.
  • Node Package Manager version 6.7 (usually ships with Node installation).
  • Angular CLI version 7.0
  • The latest version of Angular (version 7)
1// run the command in a terminal
2    ng version

Confirm that you are using version 8, and update to 8 if you are not.

  • Download an Angular quick starter project here to follow through the demonstrations.
  • Unzip the project and initialize the Node modules in your terminal with this command:
    npm install

Other things that will be nice-to-haves are:

  • A working knowledge of the Angular framework at a beginner level.
  • Familiarity with the Angular constructor will be a plus but not a requirement.

Lifecycle hooks

Every Angular component goes through the process of creation, then Angular goes on to execute all the functions it was created to execute and then go to possible destruction, this is called the lifecycle of a component. Angular does this by creating the component, rendering it as well as creating and rendering all its children. Then Angular checks for changes in the data properties or in the DOM, and makes the appropriate updates and finally when it is done, destroys it then removes it from the DOM.

Angular offers lifecycle hooks that provide visibility into these key life moments and the ability to act when they occur.

There are eight lifecycle hooks in Angular:

  • ngOnChanges()
  • ngOnInit()
  • ngDoCheck()
  • ngAfterContentInit()
  • ngAfterContentChecked()
  • ngAfterViewInit()
  • ngAfterViewChecked()
  • ngonDestroy()

New concept: content projection

This concept is very important and will help you to properly understand the four of the Angular lifecycle hooks: ngAfterContentInit(), ngAfterContentChecked(), ngAfterViewInit(), ngAfterViewChecked(). It will be briefly treated in this section. If you have a custom Angular component you are displaying in your template component.html file, you are allowed to have child elements inside your custom component. Here is a good example:

1<select>
2    <h2>Vote your favorite halloween party</h2>
3    <option value="100">Vote APC</option>
4    <option value="100">Vote PDP</option>
5    <option value="100">Vote APGA</option>
6    </select>

This is a select statement block for voting from a group of dumb party names to throw on Halloween. In Angular you can create your own custom element like the select statement like this:

1<my-party-component>
2    <h2>Vote your favorite party</h2>
3    <option value="100">Vote APC</option>
4    <option value="100">Vote PDP</option>
5    <option value="100">Vote APGA</option>
6    </my-party-component>

The problem that content projection solves is efficiency for working with child components. Using the above illustration, if you had in the CSS file two classes called pink and green that sets the background color of an element to pink or green. To apply the classes on the child component can look very cumbersome and with a lot of repetition.

1<my-party-component>
2    <h2>Vote your favorite party</h2>
3    <option class="pink" value="100"><h3>Vote APC</h3></option>
4    <option class="green" value="100"><span>Vote PDP</span></option>
5    <option class="pink" value="100"><h3>Vote APC</h3></option>
6    </my-party-component>

This can however be reduced to one line of code with content projection in the my-party-component definition:

1<ng-content select="span"></ng-content>
2    <ng-content select="h3"></ng-content>

Lifecycle hooks explained

In this article you will be introduced to every one of them, why they were built and how they are used. After creating a component by calling its constructor, Angular calls the lifecycle hook methods in the following sequence at specific moments:

ngOnChanges()

This is the very first lifecycle hook, it is called right after your class gets initialized and the component is created the ngOnChanges() is called. You might want to wonder why ngOnInit hook is not called first, but that is because Angular counts that very first class initialization as a data property change. So the hook that gets called once a data property change (like resetting values) occurs is ngOnChanges(). This hook is basically called after the constructor is called and any other time there is a property change inside your component.

Open up the starter project you downloaded in VS Code and open the app.component.ts file inside the app folder. It should look like this:

1// src/app/app.component.ts
2    import { Component } from '@angular/core';
3    @Component({
4    selector: 'app-root',
5    templateUrl: './app.component.html',
6    styleUrls: ['./app.component.css']
7    })
8    export class AppComponent {
9    title = 'ngcanvas';
10    }

To test out the ngOnChanges hook, copy in the code below inside this file:

1// src/app/app.component.ts
2    import { Component, OnChanges } from '@angular/core';
3    @Component({
4    selector: 'app-root',
5    templateUrl: './app.component.html',
6    styleUrls: ['./app.component.css']
7    })
8    export class AppComponent implements OnChanges {
9    ngOnChanges(changes: import("@angular/core").SimpleChanges): void {
10    }
11    title = 'ngcanvas';
12    constructor(){
13    alert("1. on changes called");
14    }
15    }

Here we have brought in the ngOnChanges hook from Angular and have initialized it with an alert statement in the constructor. If you run the application, the alert will pop up before the component will be loaded.

ngOnInit()

This is the second lifecycle hook called by Angular, it is called right after the very first ngOnChanges hook is called. It is only called once, it initializes the component, sets and displays component input properties. It is the most important lifecycle hook in Angular as it signals the activation of the created component. For the fact that this hook is called only once, it is therefore great for fetching data from external sources like servers and APIs.

To test this out, add the ngOnInit hook syntax to the class with the code below:

1// src/app/app.component.ts
2    import { Component, OnChanges, OnInit } from '@angular/core';
3    @Component({
4    selector: 'app-root',
5    templateUrl: './app.component.html',
6    styleUrls: ['./app.component.css']
7    })
8    export class AppComponent implements OnChanges, OnInit {
9    ngOnInit(): void {
10    alert("2. on init is called");
11    }
12    ngOnChanges(changes: import("@angular/core").SimpleChanges): void {
13    }
14    title = 'ngcanvas';
15    constructor(){
16    alert("1. on changes called");
17    }
18    }

You will see the alerts pop up in the right sequence as it is called, this will be true even if ngOnInit comes first from a top-down analysis.

ngDoCheck()

This is the third Angular lifecycle hook that gets called on a component. It is called during every change detection run, Angular has an internal system that goes around the component processes every so often looking for changes that the compiler cannot detect on its own. This hook is called at every change detection run, usually after the ngOnInit hook is called.

To test this, copy in the code below into the app.component.ts file:

1// src/app/app.component.ts
2    import { Component, OnChanges, OnInit, DoCheck } from '@angular/core';
3    @Component({
4    selector: 'app-root',
5    templateUrl: './app.component.html',
6    styleUrls: ['./app.component.css']
7    })
8    export class AppComponent implements OnChanges, OnInit, DoCheck {
9    ngDoCheck(): void {
10    alert("3. do check is called");
11    }
12    ngOnInit(): void {
13    alert("2. on init is called");
14    }
15    ngOnChanges(changes: import("@angular/core").SimpleChanges): void {
16    }
17    title = 'ngcanvas';
18    constructor(){
19    alert("1. on changes called");
20    }
21    }

You will see the alerts pop up in the right sequence here again, not minding the hierarchy of presentation.

ngAfterContentInit()

This is the fourth lifecycle hook Angular calls after a component has been initialized. This hook is called only once immediately after the first ngDoCheck hook is called, it is a kind of ngDoCheck but for content projected into the component view with ng-content. You may refer to the brief content projection summary at the beginning of this post again.

At this point you must have noticed the amazing power of Angular with intellisense in VS Code to handle imports and also initialization of these hooks perfectly.

1// src/app/app.component.ts
2    import { Component, OnChanges, OnInit, DoCheck, AfterContentInit } from '@angular/core';
3    @Component({
4    selector: 'app-root',
5    templateUrl: './app.component.html',
6    styleUrls: ['./app.component.css']
7    })
8    export class AppComponent implements OnChanges, OnInit, DoCheck, AfterContentInit {
9    ngAfterContentInit(): void {
10    alert("4. after content init called");
11    }
12    ngDoCheck(): void {
13    alert("3. do check is called");
14    }
15    ngOnInit(): void {
16    alert("2. on init is called");
17    }
18    ngOnChanges(changes: import("@angular/core").SimpleChanges): void {
19    }
20    title = 'ngcanvas';
21    constructor(){
22    alert("1. on changes called");
23    }
24    }

ngAfterContentChecked()

This is the fifth lifecycle hook Angular calls after a component has been initialized. It is called after the content projected into a component view is initialized, after the ngAfterContentInit hook and every subsequent ngDoCheck hook is called.

Exercise: To test this hook, follow the pattern in the previous hooks above and achieve create the alert for this.

If you get any error warnings on your app component, hover over it to get a quick fix preview you can use.

ngAfterViewInit()

This is the sixth lifecycle hook Angular calls after a component has been initialized. It is called only once after the very first ngAfterContentChecked hook is called. It is called after Angular initializes component views and the subsequent child views under each component, this will have to include the views displayed through content projection too and that is why it is called after the ngAfterContentChecked hook.

Exercise: To test this hook, follow the pattern in the previous hooks above and achieve create the alert for this.

ngAfterViewChecked()

This is the seventh lifecycle hook Angular calls after a component has been initialized. It is called after Angular checks the component views and the subsequent child views under each component for changes, this includes the views displayed through content projection too. It is called after the ngAfterViewInit hook and every subsequent ngAfterContentChecked hook.

Exercise: To test this hook, follow the pattern in the previous hooks above and achieve create the alert for this.

ngOnDestroy()

This is the last Angular lifecycle hook, it is called just before the component is removed from the DOM. Inside it clean up of the component is done, from detaching event handlers to unsubscribing from observables.

Exercise: To test this hook, follow the pattern in the previous hooks above and achieve create the alert for this. You will also notice that ngOnDestroy hook is not called, that is because the DOM has not been removed, if you have an unsubscribe statement inside it for instance, it will get called. Your final app.component.ts file should look like this:

1// src/app/app.component.ts
2    import { Component, OnChanges, OnInit, DoCheck, AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy } from '@angular/core';
3    @Component({
4    selector: 'app-root',
5    templateUrl: './app.component.html',
6    styleUrls: ['./app.component.css']
7    })
8    export class AppComponent implements OnChanges, OnInit,
9    DoCheck, AfterContentInit, AfterContentChecked, AfterViewInit,
10    AfterViewChecked, OnDestroy{
11    ngOnChanges(changes: import("@angular/core").SimpleChanges): void {
12    }
13    ngOnInit(): void {
14    alert("2. on init is called");
15    }
16    ngDoCheck(): void {
17    alert("3. do check is called");
18    }
19    ngAfterContentInit(): void {
20    alert("4. after content init called");
21    }
22    ngAfterContentChecked(): void {
23    alert("5. after content check called");
24    }
25    ngAfterViewInit(): void {
26    alert('6. after view init called');
27    }
28    ngAfterViewChecked(): void {
29    alert('7. after view init checked');
30    }
31    ngOnDestroy(): void {
32    alert('8. on destroy called');
33    }
34    title = 'ngcanvas';
35    constructor(){
36    alert("1. on changes called");
37    }
38    }

The ideal behavior is for the ngDoCheck, ngAfterContentChecked and ngAfterViewChecked hooks to be called multiple times as changes occur so do not be surprised they get called more than once.

Conclusion

You have been introduced to the various lifecycle hooks in Angular, now you know the basics and the reason behind the hooks you have always used in your workflow. You also know about content projection and how it relates to Angular lifecycle hooks.Here is the link to the complete project with all the hooks on GitHub. Happy hacking!