Home  >  Angular

Angular 2/4 OnInit and OnDestroy Example

By Arvind Rai, August 29, 2017
This page will walk through Angular OnInit and OnDestroy example. Component and directive has a full lifecycle managed by Angular. OnInit and OnDestroy interface has methods ngOnInit() and ngOnDestroy() respectively. ngOnInit() is called only one time after the component/directive is constructed and ngOnDestroy() is called just before component/directive is destroyed. ngOnInit() is used to perform complex logic and fetching data. ngOnDestroy() is used to release resources to avoid memory leaks. constructor should be used only for local variable initializations. All complex logic and data fetching related task should be performed in ngOnInit() so that initializing component/directive will be easy and we need not to think about their complexity. Now we will provide complete example of OnInit and OnDestroy using component and directive.

Technologies Used

Find the technologies being used in our example.
1. Angular 4.2.4
2. TypeScript 2.3.3
3. Node.js 6.10.1
4. Angular CLI 1.3.1
5. Angular Compiler CLI 4.2.4

Project Structure

Find the project structure of our demo application.
angular-demo
|
|--src
|   |
|   |--app 
|   |   |
|   |   |--app.component.ts
|   |   |--app.component.html
|   |   |--cp1.component.ts
|   |   |--counter.component.ts
|   |   |--cp.directive.ts
|   |   |--cp2.component.ts
|   |   |--cp2.component.html
|   |   |--log.ts
|   |   |--logger.service.ts
|   |   |--person.ts
|   |   |--app.module.ts
|   |   
|   |--main.ts
|   |--index.html
|   |--styles.css
|
|--node_modules
|--package.json

OnInit

OnInit interface is a lifecycle hook. It has a method ngOnInit(). It is called after data-bound properties of component/directive are initialized. ngOnInit() is called only once. In the lifecycle sequence, ngOnInit() is called just after first ngOnChanges() call. OnInit can be implemented by component, directive, pipe etc. ngOnInit() can be used for following purposes.
1. Perform complex initialization in ngOnInit() and not in constructor.
2. If we need to fetch data then it should be done in ngOnInit() and not in constructor so that we should not worry while initializing component. A constructor should perform only local variable initialization.

For the example a component will implement OnInit as following.
@Component({
   ---
})
export class CounterComponent implements OnInit { 
  ngOnInit() {
    ---
  }
  ---
}

OnDestroy

OnDestroy interface is a lifecycle hook. It has a method ngOnDestroy(). It is called for cleanup logic when a component, directive, pipe or service is destroyed. ngOnDestroy() is called just before component/directive is about to be destroyed by Angular. It can be used for following purposes.
1. Stop interval timers.
2. Unsubscribe Observables.
3. Detach event handlers.
4. Free resources that will not be garbage collected automatically.
5. Unregister all callbacks.

If we don't perform the above task in ngOnDestroy() then memory leaks are possible. For the example a component will use OnDestroy as following.
@Component({
   ---
})
export class CounterComponent implements OnDestroy { 
  ---
  ngOnDestroy() { 
   ---
  }
}

OnInit and OnDestroy using Directive

Here we will provide the use of OnInit and OnDestroy using directive. We will create service for logging that will be LoggerService. In directive when ngOnInit() and ngOnDestroy() will be called then it will set a log using LoggerService.
cp.directive.ts
import { Directive, OnInit, OnDestroy, Input } from '@angular/core';
import { LoggerService } from './logger.service';
import { Log } from './log';

@Directive({
	 selector: '[cp]'
})
export class CPDirective implements OnInit, OnDestroy {
  @Input('cp')
  personName: string;   
  constructor(private loggerService: LoggerService) {}
  ngOnInit() {
	  this.loggerService.createCP2Log(new Log('c', this.personName + ' is created.'));
  }
  ngOnDestroy() { 
	  this.loggerService.createCP2Log(new Log('r', this.personName + ' is removed.'));
  }
} 
log.ts
export class Log {
	constructor(public logType: string, public message: string) {}
} 
logger.service.ts
import { Injectable } from '@angular/core';
import { Log } from './log';

@Injectable()
export class LoggerService {
   private allCP2Logs: Log[] = []; 
   private cp1Log = new Log('', '');   
   createCP2Log(log: Log) {
	   this.allCP2Logs.push(log);
   }	   
   getAllCP2Logs() {
	   return this.allCP2Logs;
   }
   setCP1Log(logType: string, message: string) {
	   this.cp1Log.logType = logType;
           this.cp1Log.message = message;
   }
   getCP1Log() {
	   return this.cp1Log;
   }   
} 
We will add and delete persons in our demo and spy them using directive. The array of persons will be iterated using ngFor. For each and every row, our directive cp will spy the addition and deletion of persons. We will pass person name to directive. When person will be added, ngOnInit() of directive will be called and when person will be removed , ngOnDestroy() of directive will be called. We will also display logs of addition and removal of persons.
cp2.component.ts
import { Component, OnInit } from '@angular/core';
import { Person } from './person';
import { LoggerService } from './logger.service';
import { Log } from './log';

@Component({
   selector: 'app-cp2',
   templateUrl: './cp2.component.html'
})
export class CP2Component implements OnInit { 
  persons: Person[] = [];
  name: string;
  allLogs: Log[] = []; 
  constructor(private loggerService: LoggerService) {}  
  ngOnInit() {
	 this.allLogs = this.loggerService.getAllCP2Logs();  
  }
  add() {
	let personId = 0;
	let maxIndex = this.persons.length - 1;
	if (maxIndex === -1) {
	      personId = 1;
	} else {
	      let personWithMaxIndex = this.persons[maxIndex];
	      personId = personWithMaxIndex.id + 1;
	}
	this.persons.push(new Person(personId, this.name));
	this.name = '';
  }
  remove(personId: number) {
        let item = this.persons.find(ob => (ob.id === personId));
        let itemIndex = this.persons.indexOf(item);

        this.persons.splice(itemIndex, 1);
  }
} 
cp2.component.html
<div>
 <p>Add New Person <input [(ngModel)]="name">
 <button type="button" (click)="add()">Add</button> </p>
</div> 

<div *ngFor="let p of persons" [cp]="p.name">
    {{p.name}} |
    <font color='blue'><a href="javascript:void" (click)="remove(p.id)"> Remove </a></font>
</div>

<div>
 <br/><b>--- Logging ---</b>
 <ng-template ngFor let-log [ngForOf]= "allLogs">
    <ng-template [ngIf]= "log.logType === 'c' " >
	   <br/><font color= 'green'>{{log.message}}</font>
    </ng-template>
    <ng-template [ngIf]= "log.logType === 'r' " style='color: red'>
	   <br/><font color= 'red'>{{log.message}}</font>
    </ng-template>
 </ng-template> 
</div> 
person.ts
export class Person {
	constructor(public id: number, public name: string) {}
} 

OnInit and OnDestroy using Component

Here we will provide the use of OnInit and OnDestroy using component. We will create a component that will be included within another component using selector. Find the component.
cp1.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { LoggerService } from './logger.service';
import { Log } from './log';

@Component({
   selector: 'app-cp1',
   template: `
       <b>--- This is CP1Component ---</b>
   `
})
export class CP1Component implements OnInit, OnDestroy { 
  constructor(private loggerService: LoggerService) {}  
  ngOnInit() {
	  this.loggerService.setCP1Log('c', 'Component created');
  }
  ngOnDestroy() { 
	  this.loggerService.setCP1Log('r', 'Component destroyed');
  }
}
Using ngIf we will add and remove CP1Component in parent component AppComponent . When CP1Component will be added, ngOnInit() of that component will be called and when this component is removed, ngOnDestroy() of that component will be called. We will log addition and removal of component in parent component AppComponent .
app.component.ts
import { Component, OnInit } from '@angular/core';
import { LoggerService } from './logger.service';
import { Log } from './log';

@Component({
   selector: 'app-root',
   templateUrl: './app.component.html'
})
export class AppComponent implements OnInit { 
   cp1log: Log;
   constructor(private loggerService: LoggerService) {}  
   showCP1 = true;
   showCounter = true;
   ngOnInit() {
	   this.cp1log = this.loggerService.getCP1Log();
   }
   onToggleCP1() {
	   this.showCP1 = (this.showCP1 === true)? false : true;
   }
   onToggleCounter() {
	   this.showCounter = (this.showCounter === true)? false : true;
   }   
} 
app.component.html
<h3>OnInit and OnDestroy using Component</h3>
<b>Example-1:</b> <br/><br/>
<button type="button" (click)="onToggleCP1()">Toggle</button><br/><br/>
<div *ngIf="showCP1">
  <app-cp1></app-cp1>   
</div>
<br/>
<div *ngIf="cp1log">
	<div *ngIf="cp1log.logType === 'c'">
	  <font color="green">{{cp1log.message}}</font>   
	</div>
	<div *ngIf="cp1log.logType === 'r'">
	  <font color="red">{{cp1log.message}}</font>  
	</div>
</div>

<br/><br/><b>Example-2:</b> <br/><br/>
<button type="button" (click)="onToggleCounter()">Toggle Counter</button><br/><br/>
<div *ngIf="showCounter">
  <app-cunter></app-cunter>
</div>

<h3>OnInit and OnDestroy using Directive</h3>	   
<app-cp2></app-cp2> 
Now find the example of OnInit and OnDestroy to start and clear interval as real time scenario. We will create CounterComponent that will start counter with setInterval() using ngOnInit() method and will clear interval instance using ngOnDestroy() method. In AppComponent we will add and remove CounterComponent using ngIf . When CounterComponent will be added, the counter will start because ngOnInit() will be called. When we remove this component, then ngOnDestroy() will be called that will clear interval instance. Hence there is no possibility of memory leak because of setInterval() . Find the CounterComponent.
counter.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';

@Component({
   selector: 'app-cunter',
   template: `
    {{counter}}
   `
})
export class CounterComponent implements OnInit, OnDestroy { 
  counter = 0;
  intervalId: any;
  ngOnInit() {
    this.startCounter();  
    console.log('Interval started.');
  }
  startCounter() {
    this.intervalId = setInterval(() => {
       this.counter += 1;
    }, 1000);
  }  
  ngOnDestroy() { 
    clearInterval(this.intervalId);
    console.log('Interval cleared.');
  }
} 
We are adding and removing above component in AppComponent. Now find the application module.
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

import { AppComponent }  from './app.component';
import { CP1Component } from './cp1.component';
import { CP2Component } from './cp2.component';
import { CounterComponent } from './counter.component';
import { CPDirective } from './cp.directive';
import { LoggerService } from './logger.service';

@NgModule({
  imports: [     
        BrowserModule,
	FormsModule
  ],
  declarations: [
        AppComponent,
	CP1Component,		
	CP2Component,
	CounterComponent,
	CPDirective
  ],
  providers: [
        LoggerService
  ],
  bootstrap: [
        AppComponent
  ]
})
export class AppModule { } 

Run Demo Application

To run the demo application, find following steps.
1. Download source code using download link given below on this page.
2. Use downloaded src in your angular CLI application. To install angular CLI, find the link.
3. Run ng serve using command prompt.
4. Now access the URL http://localhost:4200
Angular 2/4 OnInit and OnDestroy Example

References

OnDestroy
Lifecycle Hooks

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
FIND MORE TUTORILAS


©2019 concretepage.com | Privacy Policy | Contact Us