Sunday, November 5, 2023

Angular Component Life Cycle Step by Step Example

Create a two new components 

Parent and Child Components as shown below









ngOnChanges

The Angular invokes the ngOnChanges life cycle hook whenever any data-bound input property of the component or directive changes

Initializing the Input properties is the first task angular carries during the change detection cycle.

Input properties are those properties which we define using the @Input decorator. It is one of the ways by which a parent communicates with the child component.

It also fires upon initialization of input data. The hook receives one optional parameter of type SimpleChanges


Example

Child Component.ts


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

@Component({
  selector: 'app-child-component',
  templateUrl: './child-component.component.html',
  styleUrls: ['./child-component.component.css']
})
export class ChildComponentComponent implements OnChanges{
  @Input() data: string | undefined;
  lifecycleTicks: number = 0;
  constructor() {
    console.log('child constructor')
  }
 
  ngOnChanges(changes: SimpleChanges): void {
    console.log('ng on changes child component')
    this.lifecycleTicks++;
  }
}


child component.html

<h3>Child Component</h3>
  <p>TICKS: {{ lifecycleTicks }}</p>
  <p>DATA: {{ data }}</p>


appModule.ts














Parent Component.html

<h1>ngOnChanges Example</h1>
<app-child-component [data]="arbitraryData"></app-child-component>

Parent Component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-parent-component',
  templateUrl: './parent-component.component.html',
  styleUrls: ['./parent-component.component.css']
})
export class ParentComponentComponent {
  arbitraryData: string = 'initial';
  constructor() {
    console.log('Parent constructor')
    setTimeout(() => {
      this.arbitraryData = 'final';
    }, 5000);
  }
}


Output






Note, from the above example we can also get the previous and current values as
shown below


  ngOnChanges(changes: SimpleChanges): void {
    console.log('ng on changes child component')
    for (let propName in changes) {
      let chng = changes[propName];
      let cur  = JSON.stringify(chng.currentValue);
      let prev = JSON.stringify(chng.previousValue);
    }
    this.lifecycleTicks++;
  }




ngOnInit

Fires once upon initialization of a component’s input-bound (@Input

properties. 

This hook is fired only once and immediately after its creation (during the first change detection).

The hook does not fire as Child Component receives the input data. 

Rather, it fires right after the data renders to the  ChildComponent template.

This is a perfect place where you want to add any initialization logic for your component. 


child component.ts

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

@Component({
  selector: 'app-child-component',
  templateUrl: './child-component.component.html',
  styleUrls: ['./child-component.component.css']
})
export class ChildComponentComponent implements OnInit{
  @Input() data: string | undefined;
  lifecycleTicks: number = 0;
  constructor() {
    console.log('child constructor')
  }
  ngOnInit(): void {
    console.log('ngOnInit child component')
    this.lifecycleTicks++;
  }
}

Child Component.html

<h3>Child Component</h3>
  <p>TICKS: {{ lifecycleTicks }}</p>
  <p>DATA: {{ data }}</p>


Parent Component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-parent-component',
  templateUrl: './parent-component.component.html',
  styleUrls: ['./parent-component.component.css']
})
export class ParentComponentComponent {
  arbitraryData: string = 'initial';
  constructor() {
    console.log('Parent constructor')
    setTimeout(() => {
      this.arbitraryData = 'final';
    }, 5000);
  }
}

Parent Component.html


<h1>ngOnInit Example</h1>
<app-child-component [data]="arbitraryData"></app-child-component>



Output



















ParentComponent binds input data to the ChildComponent. ChildComponent receives this
data through its @Input property. The data renders to the template. ngOnInit fires.
After five seconds, the setTimeout callback triggers.
ParentComponent mutates the data source of ChildComponent’s input-bound property.
ngOnInit DOES NOT FIRE.



ngDoCheck

Angular invoke it after the ngOnChanges ngOnInit hooks.

It fires with every change detection cycle. Angular runs change detection frequently.

It can create performance issues when implemented incorrectly.


Example










.ts Changes


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

@Component({
  selector: 'app-ng-do-check',
  templateUrl: './ng-do-check.component.html',
  styleUrls: ['./ng-do-check.component.css']
})
export class NgDoCheckComponent implements DoCheck {
  lifecycleTicks: number = 0;
  oldTheData: string | undefined;
  data: string[] = ['initial'];

  constructor(private changeDetector: ChangeDetectorRef) {
    this.changeDetector.detach(); // lets the class perform its own change detection

    setTimeout(() => {
      this.oldTheData = 'final'; // intentional error
      this.data.push('intermediate');
    }, 3000);

    setTimeout(() => {
      this.data.push('final');
      this.changeDetector.markForCheck();
    }, 6000);
  }

  ngDoCheck() {
    console.log(++this.lifecycleTicks);

    if (this.data[this.data.length - 1] !== this.oldTheData) {
      this.changeDetector.detectChanges();
    }
  }
}


.html Changes

<h1>ngDoCheck Example</h1>
<p>DATA: {{ data.length }}</p>
<p>DATA: {{ data[data.length - 1] }}</p>

Output













ngAfterContentInit

ngAfterContentInit Life cycle hook is called after the Component’s projected content has been fully initialized. Angular also updates the properties decorated with the ContentChild and ContentChildren before raising this hook. 


Example


Create two child Components and a Parent Component


















Parent Component.ts

import { Component } from '@angular/core';

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

}

Parent Component.html


<h1>ngAfterContentInit Example</h1>
  <p>I am A.</p>
  <app-child-component2>
    <h3 #BHeader>BComponent Content DOM</h3>
    <app-child-component1></app-child-component1>
  </app-child-component2>



Child Component 2.ts

import { AfterContentInit, Component, ContentChild, ElementRef, Renderer2 } from '@angular/core';
import { ChildComponent1Component } from '../child-component1/child-component1.component';

@Component({
  selector: 'app-child-component2',
  templateUrl: './child-component2.component.html',
  styleUrls: ['./child-component2.component.css']
})
export class ChildComponent2Component implements AfterContentInit {
  @ContentChild("BHeader", { read: ElementRef })
  hRef!: ElementRef;
  @ContentChild(ChildComponent1Component, { read: ElementRef })
  cRef!: ElementRef;

  constructor(private renderer: Renderer2) { }

  ngAfterContentInit() {
    this.renderer.setStyle(this.hRef.nativeElement, 'background-color', 'yellow')

    this.renderer.setStyle(this.cRef.nativeElement.children.item(0), 'background-color', 'pink');
    this.renderer.setStyle(this.cRef.nativeElement.children.item(1), 'background-color', 'red');
  }
}



Child Component2.html

<p>I am B.</p>
<ng-content></ng-content>


Child Component1. html


<p>I am C.</p>
<p>Hello World!</p>


Output
















ngOnDestroy

It fires upon a component’s removal from the view and subsequent DOM. 

The ngOnDestroy or OnDestroy hook is called just before the Component/Directive instance is destroyed by Angular


Example

Child Component.ts

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

@Component({
  selector: 'app-childcomponent',
  templateUrl: './app-destroy-listener.component.html',
  styleUrls: ['./app-destroy-listener.component.css']
})
export class AppDestroyListenerComponent implements OnDestroy,OnInit  {
  constructor() {
    console.log('ChildComponent:Constructor');
  }
 
  ngOnInit() {
    console.log('ChildComponent:OnInit');
  }
 
  ngOnDestroy() {
    console.log('ChildComponent:OnDestroy');
  }
}


Child Component.html

<p>Child Component</p>


Parent Component.ts

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

@Component({
  selector: 'app-app-destroy-listener1',
  templateUrl: './app-destroy-listener1.component.html',
  styleUrls: ['./app-destroy-listener1.component.css']
})
export class AppDestroyListener1Component  implements OnInit, OnDestroy{
  destroy: boolean = true;

  constructor() {
    console.log('Parent Component:Constructor');
  }

  toggleDestroy() {
    console.log('toogle')
    this.destroy = !this.destroy;
  }
  ngOnInit() {
    console.log('Parent Component:OnInit');
  }
 
 
  ngOnDestroy() {
    console.log('Parent Component:OnDestroy');
  }
}


Parent Component.html

<h1>ngOnDestroy Example</h1>
<button (click)="toggleDestroy()">TOGGLE DESTROY</button>
<app-childcomponent *ngIf="destroy">I can be destroyed!</app-childcomponent>


Output














On Clicking on Toogle Destroy













Again Click on Toogle Destroy




















Difference Between Constructor and ngOnInit

The Constructor is executed when the class is instantiated. It has nothing do with the angular.

The ngOnInit is Angular specific and is called when the Angular has initialized the component with all its input properties

The @Input properties are available under the ngOnInit lifecycle hook. This will help you to do some initialization stuff like getting data from the back-end server etc to display in the view

@Input properties are shows up as undefined inside the constructor







No comments:

Post a Comment

Thank you for visiting my blog

Kubernetes

Prerequisites We assume anyone who wants to understand Kubernetes should have an understating of how the Docker works, how the Docker images...