Angular Lifecycle Hooks in Practice
Tags: angular, development, web, productivity
Published: 2023-02-01 10:28:12

---
title: Angular Lifecycle Hooks in Practice
published: true
date: 2023-01-31 11:00:00 UTC
tags: angular, development, web, productivity
canonical_url: https://www.syncfusion.com/blogs/post/angular-lifecycle-hooks-in-practice.aspx
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lgpmzxcvzm6gsg5t5t6x.png
---
[Angular](https://angular.io/ "Angular") is one of the most popular front-end frameworks for building component-based robust web applications. A component in an Angular app has a lifecycle that goes through different phases, starting from its instantiation. Lifecycle hooks allow you to hook into those different phases as components are created, updated, and destroyed to gain more control over your application.

In this article, I will discuss Angular lifecycle hooks while showing when and how to use them.

## What are lifecycle hooks?

Lifecycle hooks are timed methods that get activated by Angular change detection. Since Angular continuously executes change detection on data, the conditions of the current change detection cycle determine how lifecycle hooks are used. The most vital point about lifecycle hooks is the sequence in which they are used. The execution order doesn’t change, and they execute based on a predetermined sequence of load events generated by a detection cycle.

A hook, of course, only works when it satisfies specific criteria as determined by the current change detection cycle. Some resources are only accessible when a specific hook runs. You can use lifecycle hooks to hook into essential stages in the lifecycle of a component or directive to initiate new instances, initialize change detection when required, respond to changes throughout change detection, and clean up before instance destruction.
We can group these hooks into the following two categories:

- Hooks connected to the component itself or directives:
  - **[constructor()](#constructor)**
  - **[ngOnChanges](#ngonchanges)**
  - **[ngOnInit](#ngoninit)**
  - **[ngDoCheck](#ngdocheck)**
  - **[ngOnDestroy](#ngondestroy)**
- Hooks connected to child components:
  - **[ngAfterContentInit](#ngaftercontentinit)**
  - **[ngAfterContentChecked](#ngaftercontentchecked)**
  - **[ngAfterViewInit](#ngafterviewinit)**
  - **[ngAfterViewChecked](#ngafterviewchecked)**

Now let’s look into these, one by one.

### <a name="constructor">constructor()</a>

A component lifecycle begins with the creation of a component. The **Constructor()** method is the first hook called when Angular calls **new** on a class to construct a component or directive, and it ensures that the class’s fields and subclasses are properly initialized.

At this time, we cannot access the input properties of the component. None of its subcomponents are created. Furthermore, projected content is also unavailable. After the component has been instantiated, Angular starts the component’s first cycle of change detection.

### <a name="ngonchanges">ngOnChanges</a>

**ngOnChanges** is a lifecycle hook that is invoked once on the component’s instantiation and whenever one or more data-bound input properties change before **ngOnInit()** (if the component contains **@Input** -bound inputs). It gets triggered when Angular changes the data-bound input properties or resets them. A **SimpleChanges** object with the current and previous property values is passed as an optional parameter to the method.

### <a name="ngoninit">ngOnInit</a>

The **ngOnInit** hook is invoked following the first **ngOnChanges()**. Even when **ngOnChanges()** is not called when there are no template-bound inputs, **ngOnInit()** is still invoked. It is triggered upon the completion of initializing data-bound or input properties of a component.

After the completion of child component rendering, **ngOnInit()** gets invoked. Then, even after the data source of the input-bound property gets updated within the parent component, **ngOnInit()** isn’t invoked. So, we can call the **ngOnInit()** a one-time-use hook. It solely cares about initialization.

### <a name="ngdocheck">ngDoCheck</a>

On every change detection run, **ngDoCheck()** is called immediately after **ngOnChanges()**, and on the initial run, it is called right after **ngOnInit()**. It detects and responds to changes that Angular alone cannot or will not detect. Following the execution of the default change detector, **ngDoCheck()** usually carries out change detection.

Developers can explicitly verify their data using **ngDoCheck()** as a custom change detector while combining it with **ChangeDetectorRef**. However, it is worth noting that it might lead to performance problems when mishandled.

### <a name="ngaftercontentinit">ngAfterContentInit</a>

Following the first **ngDoCheck** , the **ngAfterContentInit()** hook is executed. It gets triggered when the component or directive content has been initialized.

### <a name="ngaftercontentchecked">ngAfterContentChecked</a>

**ngAfterContentChecked** is called following **ngAfterContentInit()** and each subsequent **ngDoCheck()**. This hook gets invoked after Angular has evaluated the content projected in the directive or component.

### <a name="ngafterviewinit">ngAfterViewInit</a>

The **ngAfterViewInit** hook is executed after **ngAfterContentChecked()**. The view is always loaded immediately after the content. So, it gets triggered after Angular initializes the views and child views of the component or the view containing the directive.

Within this hook, we have access to the **ElementRef** of the **ViewChildren** after the component has been created. **ngAfterViewInit** awaits the resolution of either **@ViewChild** or **@ViewChildren** queries. The same view of the component helps us to query these elements. We can use this hook for cases where the loading of view content depends on other view components.

### <a name="ngafterviewchecked">ngAfterViewChecked</a>

The **ngAfterViewChecked** hook is called after the **ngAfterViewInit()** and every subsequent **ngAfterContentChecked()**. It is triggered after Angular has examined the component’s and child’s views or the view that holds the directive. Watch out for setting any variables here that are bound to the template. It will lead to unexpected errors.

### <a name="ngondestroy">ngOnDestroy</a>

When a component’s lifecycle is over, Angular is in charge of destroying the component. However, several essential detachment steps must be finished before the component or directive can be destroyed. **ngOnDestroy()** is the lifecycle hook responsible for carrying out these steps.

Now, let’s see how to implement Angular lifecycle hooks through a simple example.

Here, we are going to implement a simple component named **UserDetails**. Additionally, the **UserDetails** component will have a child component named **Random** to generate user IDs with a user-provided prefix randomly. You may choose to display or hide this **UserDetails** form from the main view.

![ngOnDestroy hook](https://www.syncfusion.com/blogs/wp-content/uploads/2023/01/image001.gif)

Refer to the code of the **UserDetails** component below.

```js
import { Component, Injectable, OnInit, OnChanges, DoCheck, AfterViewChecked, AfterViewInit, AfterContentInit, AfterContentChecked, OnDestroy } from "@angular/core";

@Component({
  selector: "userdetails",
  template: `
    <div>
      <h2>Name :</h2>
      <input type="text" [(ngModel)]="name" />
      <input type="text" [(ngModel)]="prefix" />
      <random
        [user]="prefix"
        (generateUserId)="onGenerateUserId($event)"
      ></random>
      <h3>UserID : {{ userid }}</h3>
    </div>
  `
})

export class UserDetails
  implements
    OnInit,
    OnChanges,
    DoCheck,
    AfterViewChecked,
    AfterViewInit,
    AfterContentInit,
    AfterContentChecked,
    OnDestroy {
      name: string = "Angular";
      prefix: string = "";
      userid: string = "";
     
      constructor() {
        this.name = "";
        console.log("Parent constructor() called");
      }
   
      onGenerateUserId(uid:string) {
        console.log("Generating UserID");
        this.userid = uid;
      }
  
      ngOnInit() {
        this.name = "John Doe";
        console.log("Parent ngOnInit() called");
      }
  
      ngOnChanges() {
        console.log("Parent ngOnChanges() called");
      }
  
      ngDoCheck() {
        console.log("Parent ngDoCheck() called");
      }
  
      ngAfterViewChecked() {
        console.log("Parent ngAfterViewChecked() called");
      }
  
      ngAfterViewInit() {
        console.log("Parent ngAfterViewInit() called");
      }
  
      ngAfterContentInit() {
        console.log("Parent ngAfterContentInit() called");
      }
  
      ngAfterContentChecked() {
        console.log("Parent ngAfterContentChecked() called");
      }
  
      ngOnDestroy() {
        console.log("Parent ngOnDestroy() called");
      }
}
```

Refer to the code of the **random ID generator** component below.

```js
import {Component, Injectable, Input, Output, EventEmitter, OnInit, OnChanges, DoCheck, AfterViewChecked, AfterViewInit, AfterContentInit, AfterContentChecked, OnDestroy} from '@angular/core'

@Component({
  selector: 'random',
  template: `
    <div>
      <input type='button' (click)='random()' value='Generate UserID' />
    </div>
  `
})

export class Random implements OnInit, OnChanges, DoCheck, AfterViewChecked, AfterViewInit, AfterContentInit, AfterContentChecked, OnDestroy{
  
  @Input() user:string;
  @Output() generateUserId: EventEmitter<string> = new EventEmitter<string>();
  
  constructor(){
   this.user = '';
   console.log('Child constructor() called');
  }
  
  random(){
    var t = new Date().getTime();
    this.generateUserId.emit(this.user + t.toString());
    console.log('random() called');
  }
  
  ngOnInit(){
    console.log('Child ngOnInit() called');
  }
  
  ngOnChanges(){
    console.log('Child ngOnChanges() called');
  }
  
  ngDoCheck(){
    console.log('Child ngDoCheck() called');
  }
  
  ngAfterViewChecked(){
    console.log('Child ngAfterViewChecked() called');
  } 
  
  ngAfterViewInit(){
    console.log('Child ngAfterViewInit() called');
  }
  
  ngAfterContentInit(){
    console.log('Child ngAfterContentInit() called');
  }
  
  ngAfterContentChecked(){
    console.log('Child ngAfterContentChecked() called');
  }
  
  ngOnDestroy(){
    console.log('Child ngOnDestroy() called');
  }
}
```

Once you click on the **Show User Details** button, the parent and child components’ constructors run first as the parent component’s initialization occurs.

The application’s main component code is as follows.

```js
//app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  name:string;
  showUserDetails: boolean;
  btnText: string;

  constructor() {
    this.showUserDetails = false;
    this.btnText = 'Show';
  }

  toggleUserDetails(){
    this.showUserDetails = !this.showUserDetails;
    this.btnText = this.showUserDetails ? 'Hide' : 'Show';
  }

}

//app.component.html
  <h2>Angular Lifecycle Events Example</h2>
    <div>
      <input type='button' (click)='toggleUserDetails()' value='{{btnText}} User Details'>
    </div>
    <div *ngIf='showUserDetails'>
      <userdetails></userdetails>
    </div>
```

**ngAfterContentInit** and **ngAfterContentChecked** are invoked immediately after **ngOnInit()** and **ngDoCheck()**. This implies that all external HTML will be first rendered. Then, the child component kicks off initializing. As previously explained, whenever any child’s **Input()**-bound properties are initialized or updated, **ngOnChanges()** will be called.

Looking closely, we can see that the child component’s **ngAfterViewInit** and **ngAfterViewChecked** hooks are coming early in the execution sequence. This indicates that the child component view will be first rendered before giving it to the parent. The parent component then relies on the assumption that its own view is finished since its child’s views are done. Therefore, the parent component’s **ngAfterViewInit** and **ngAfterViewChecked** hooks are triggered next.

The following figure shows the output flow for the **Show User Details** button click.

![Output of Show User Details button click](https://www.syncfusion.com/blogs/wp-content/uploads/2023/01/image002.png)
Once you type a letter in the text box as a user ID prefix and then click the **Generate UserID** button, you will get the console output like in the following image.

![Output of Generate UserIDs button click](https://www.syncfusion.com/blogs/wp-content/uploads/2023/01/image003.png)So the complete flow would look like the following image.

![Output of ngOnDestroy hook](https://www.syncfusion.com/blogs/wp-content/uploads/2023/01/image004.png)The parent component will be destroyed when you click the **Hide User Details** button, depending on **\*ngIf**. Since the parent is destroyed, each of its children will also be removed. This means that the parent components will be cleaned up after cleaning up the child components. The result is shown below.

![Output of Hide User Details button click event](https://www.syncfusion.com/blogs/wp-content/uploads/2023/01/image005.png)

## Resources

For more details, refer to the demo application on the [Angular Lifecycle Hooks](https://github.com/SyncfusionExamples/angular-life-cycle-hooks-demo "Angular Lifecycle Hooks GitHub demo") GitHub repository.

## Conclusion

In this article, I discussed the Angular lifecycle hooks and when, where, and why they are used in Angular app development. As our projects expand, lifecycle hooks let us precisely control how our components behave from their creation. So, it is vital to grasp the concept and practice with it to enjoy its benefits.

Thank you for reading!

Syncfusion’s [Angular UI component](https://www.syncfusion.com/angular-ui-components "Syncfusion Angular UI Components") library is the only suite you will ever need to build an app. It contains over 80 high-performance, lightweight, modular, and responsive UI components in a single package.

For existing customers, the newest Essential Studio version is available for download from the [License and Downloads](https://www.syncfusion.com/account/downloads "License and download page of Essential Studio") page. If you are not a Syncfusion customer, you can try our 30-day [free trial](https://www.syncfusion.com/downloads "Free evaluation of the Syncfusion Essential Studio") to check out the available features. Also, check out our demos on [GitHub](https://github.com/syncfusion "Syncfusion GitHub Demos").

If you have questions, contact us through our [support forums](https://www.syncfusion.com/forums "Syncfusion Support Forums"), [support portal](https://support.syncfusion.com/ "Syncfusion Support Portal"), or [feedback portal](https://www.syncfusion.com/feedback/angular "Syncfusion Feedback Portal"). We are always happy to assist you!

## Related blogs

- [What’s New in 2022 Volume 4: Essential JS 2](https://www.syncfusion.com/blogs/post/whats-new-in-2022-volume-4-essential-js-2.aspx "Blog: What’s New in 2022 Volume 4: Essential JS 2")
- [A Complete Guide to Creating a Mind Map Using Angular Diagram Component](https://www.syncfusion.com/blogs/post/mind-map-using-angular-diagram.aspx "Blog: A Complete Guide to Creating a Mind Map Using Angular Diagram Component")
- [Debug Angular Apps Easily Using Angular DevTools](https://www.syncfusion.com/blogs/post/debug-angular-apps-easily-using-angular-devtools.aspx "Blog: Debug Angular Apps Easily Using Angular DevTools")
- [Mastering Strictly Typed Reactive Forms in Angular: A Step-by-Step Guide](https://www.syncfusion.com/blogs/post/strictly-typed-reactive-forms-in-angular.aspx "Blog: Mastering Strictly Typed Reactive Forms in Angular")