Tech Incent
Angular

Angular lifecycle hooks explanation

All the components and directives have a lifecycle to angular components and directives creates, update, and destroy. We can implement the lifecycle hook interface and use the respective method to tap into any lifecycle moments. Components have more lifecycle hooks than directives.

All Angular lifecycle hooks

  1. OnInit
  2. OnChanges
  3. DoCheck
  4. AfterContentInit
  5. AfterCpntentChecked
  6. AfterViewInit
  7. AfterViewChecked
  8. OnDestroy

Note: Constructor is not a Lifecycle hook. Its typescript feature

Common lifecycle hooks methods

These general lifecycle hooks available for component and directive

  • OnInit
  • DoCheck
  • OnChange
  • OnDestroy

Lifecycle hooks only available in components

  • AfterContentInit
  • AfterContentChecked
  • AfterViewInit
  • AfterViewChecked

All angular lifecycle hooks methods

ngOnInitThis hook will call after the constructor is executed. if OnChanges was implemented, then it will call after ngOnChanges methods executed
ngOnChangesCall once before ngOnInit methods and when an input/output binding value changes
ngDoCheckCalled immediately after ngOnChanges on every change detection run, and immediately after ngOnInit on the first run
ngAfterContentInitCalled once after the first ngDoCheck
ngAfterContentCheckedCalled after ngAfterContentInit and every subsequent ngDoCheck
ngAfterViewInitCalled once after the first ngAfterContentChecked
ngAfterViewCheckedCalled after the ngAfterViewInit and every subsequent ngAfterContentChecked
ngOnDestroyThis hook will call before components destroy
Angular lifecycle hooks

How to implement angular hooks?

  1. Add to implement hooks interface in component or directive class.
  2. Define particular hooks methods.
OnInit hooks integrated

Create structure for example to better undertanding

I will generate a new project. it will contain parent and child components. So I will build this structure? when I explain these hooks, I will show code examples and screenshots to understand what’s happening.

generate project

ng new angular-lifecyle-hooks
cd angular-lifecyle-hooks

Parent component

Generate parent component

ng g c parent

Render parent component in app.component.html file

<app-parent></app-parent>

Child component

Generate child component

ng g c child

Render child component in the parent component. Define child selector inside parent.component.html file

<p>This parent Element</p>
<hr>
<app-child></app-child>

#1 OnInit

OnInit hook provides ngOnInit methods for components or directives to handle any additional initialization tasks. ngOnInit will be invoked when the component has initialized. This hook method will be called only once after the ngOnChanges methods execute, If the OnChanges hook does not implement in the component then it will call after the constructor is executed. Mostly, We use ngOnInit for doing the initialization.

When we create a component using Angular CLI, we can see the OnInit hook has been implemented. But we can do it manually.

Use case example

Implement User list API call

import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit {
  userList: any
  constructor(private http: HttpClient) {
    console.log('Parent constructor is called')
  }


  ngOnInit(): void {
    console.log('Parent ngOnInit is called')
    this.getUserList()
  }
  getUserList(): void {
    this.http.get('https://jsonplaceholder.typicode.com/users').subscribe((data) => {
      this.userList = data;
      console.log(this.userList)
    })
  }
}

Here are console logs

OnInit hooks example result

#2 OnChanges

OnChanges hook provides ngOnChanges method for component and directive. ngOnChanges will be called once After the constructor is executed and It will be called whenever the data-bound @Input properties changes. it’s not normal HTML input. It’s angular data-binding input.

ngOnChanges can pass the one argument interface of SimpleChanges. When a component is first to run, this argument contains all the list of @Input. But when the single @Input change this argument contain changed @Input.

Let’s see example:

Edit parent.component.ts file.

Define searchInput and anotherInput properties in parent.component.ts file.

// ...
export class ParentComponent implements OnInit {
  searchInput: any;
  anotherInput: any;
  constructor(private http: HttpClient) {
    console.log('Parent constructor is called')
  }
  // ...
}

In parent.component.html file

<p>This parent Element</p>
<input type="text" [(ngModel)]="searchInput" placeholder="Parent Input" />
<hr>
<app-child *ngIf="showChild" [searchInput]="searchInput" [anotherInput]="anotherInput"></app-child>

In child.component.ts file

import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit, OnChanges {
  @Input() searchInput!: string;
  @Input() anotherInput!: string
  constructor() {
    console.log('Child constructor is called')
  }
  ngOnInit(): void {
    console.log('Child ngOnInit is called')
    
  }
  ngOnChanges(changes: SimpleChanges): void {
      console.log('Child OnChanges'),
      console.log('Simple Changes', changes)
  }
}
ngOnChanges
ngOnChanges preview

#3 DoCheck

DoCheck will be invoked when the change detector of the given is invoked. It is called immediately after ngOnChanges methods on every change detection run, and immediately after ngOnInit on the first run.

import { Component, DoCheck, OnInit } from '@angular/core';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit, DoCheck {
  constructor(private http: HttpClient) {
    console.log('Parent constructor is called')
  }
  ngOnInit(): void {
    console.log('Parent ngOnInit is called')
  }
  ngDoCheck(): void {
    console.log('Parent ngDoCheck')
  }
}

Note *: We should avoid using ngOnChanges and ngDoCheck in the same component. Sometimes, the change detection triggers another change and it became an infinite loop

Content projection Example for component lifecycle hook

Before start only available component hooks explanation. I need to create the content projection. Assume I wanted to send project some content to the child component from the parent component. let’s implement content projection

Send project from parent component

In the parent.component.html file. Create projection content and I select projection content with projectedContent name.

<!-- other content -->
<app-child [searchInput]="searchInput">
  <!-- Projection content -->
  <div #projectedContent>Hello, this is project from parent</div>
</app-child>

Show output in child component

In the child.component.html file. I added <ng-content> an element where I want the projected content to appear.

<!-- content project render here -->
<ng-content></ng-content>

Now select projection content

In the child.component.ts file. I can access the template ref variable with a build-in ContentChild selector.

import { Component, OnInit, ContentChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
  @ContentChild('projectedContent') projectedContent!: ElementRef;
  // ...
  constructor() {
    console.log('Child constructor is called')
  }
  ngOnInit(): void {
    console.log('Child ngOnInit is called')
  }
  // ...
}

#4 AfterContentInit

AfterContentInit hook methods ngAfterContentInit will be called only once after the first ngDoCheck.

I need to add the AfterContentInit hook in the component class as implements. In this example, I will console.log our projection content (#projectedContent) in ngOnInit and ngAfterContentInit.

Edit child.component.ts file

import { AfterContentInit, Component, ContentChild, ElementRef, Input, OnInit } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit, OnChanges, AfterContentInit, OnDestroy {
  @Input() searchInput!: string;
  @ContentChild('projectedContent') projectedContent!: ElementRef;
  constructor() {
    console.log('Child constructor is called')
  }
  ngOnInit(): void {
    console.log('Child ngOnInit is called')
    console.log('OnInit content', this.projectedContent)
    
  }
  ngAfterContentInit(): void {
    console.log('Child after content init')
    console.log('AfterContentInit content', this.projectedContent)
  }
}

Result preview

AfterContentInit preview
AfterContentInit preview result

You can see ngOnInit methods content undefined, But ngAfterContentInit method can select projection content as a Angular native element.

#5 AfterContentChecked

ngAfterContentChecked will be called after ngAfterContentInit and every subsequent ngDoCheck’

Let’s implement ngAfterContentChecked example

import { AfterContentChecked, AfterContentInit, Component, ContentChild, ElementRef, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit, AfterContentInit, AfterContentChecked {
  @Input() searchInput!: string;
  @ContentChild('projectedContent') projectedContent!: ElementRef;
  constructor() {
    console.log('Child constructor is called')
  }
  ngOnInit(): void {
    console.log('Child ngOnInit is called')
    console.log('OnInit content', this.projectedContent)
    
  }
  ngAfterContentInit(): void {
    console.log('Child AfterContentInit')
    console.log('AfterContentInit content', this.projectedContent)
  }
  ngAfterContentChecked(): void {
    console.log('Child AfterContentChecked')
  }
}

Preview

aftercontentchecked

#6 AfterViewInit

ngAfterViewInit will be called once after the first ngAfterContentChecked

// ...
export class ChildComponent implements OnInit, AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked {
  // ...
  ngAfterViewInit(): void {
    console.log('Child AfterViewInit')
  }
}

#7 AfterViewChecked

ngAfterViewChecked will be called after ngAfterViewIint and every subsequent ngAfterContentChecked

// ...
export class ChildComponent implements AfterViewChecked {
  // ...
  ngAfterViewChecked(): void {
    console.log('Child AfterViewChecked')
  }
}

#8 OnDestroy

OnDestroy will be called one just before the component is removed from the DOM, in other words when the component is destroyed from the DOM.

OnDestroy is used for any custom cleanup. And this hook is primarily used to unsubscribe from our observable streams and to disconnect event handlers to avoid memory leaks.

how to use onDestroy Hook?

The components or directives class implements the OnDestroy interface. OnDestiry hook interface provide ngOnDestroy() method.

...
@Component({
  ...
})
export class ParentComponent implements OnDestroy {
  constructor(private http: HttpClient) {
    console.log('Parent constructor is called')
  }

  ngOnDestroy(): void {
    console.log('Parent OnDestroy is called')
  }
}

Source: https://angular.io/guide/lifecycle-hooks

Example Source Code: https://github.com/techincent/angular-lifecycle-hooks.git

Related posts

Angular Pure Bootstrap 5 Sidenav

Sajal Mia

Most Commonly Used RxJS Operators With Example

Sajal Mia