Angular Lifecycle Hooks
Lifecycle hooks are methods Angular calls at key moments (create, input changes, view init, destroy) so you can set up, react to changes, access template refs, and clean up.
Lifecycle Essentials
- What: Lifecycle hooks are methods Angular calls at key moments (init, input changes, view init, destroy).
- Setup: Use
ngOnInitafter inputs are set. - React: Handle input changes in
ngOnChanges. - DOM ready: Use
ngAfterViewInitto access@ViewChildrefs. - Cleanup: Release timers/subscriptions/listeners in
ngOnDestroy.
import { OnInit, OnDestroy, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
export class Demo implements OnInit, AfterViewInit, OnDestroy {
@ViewChild('box') box!: ElementRef<HTMLInputElement>;
intervalId: any;
ngOnInit() { /* setup after inputs */ }
ngAfterViewInit() { this.box.nativeElement.focus(); }
ngOnDestroy() { clearInterval(this.intervalId); }
}
// Template: <input #box>
Example explained
ngOnInit: Run setup that needs inputs already bound.@ViewChild+ngAfterViewInit: Access and focus the input only after the view is initialized.ngOnDestroy: Clean up timers/listeners to prevent leaks.
Notes:
- Related: See Components for creating views, Templates for markup and refs, and Directives for structural rendering like
*ngIfused in examples. - Avoid DOM access in constructors.
Lifecycle Hooks
- Toggle lifecycle: Showing a component (e.g., with
*ngIf) runsngOnInit; hiding it runsngOnDestroy. - Do/undo work: Start timers/subscriptions on init, clear/unsubscribe on destroy.
export class Child implements OnInit, OnDestroy {
intervalId: any;
ngOnInit() { this.intervalId = setInterval(() => {/* ... */}, 1000); }
ngOnDestroy() { clearInterval(this.intervalId); }
// <child-cmp *ngIf="show"></child-cmp>
Example explained
ngOnInit: Starts a timer when the component is created.ngOnDestroy: Clears the timer when the component is removed.*ngIf: Toggling the condition creates/destroys the child, invoking the hooks.
Example
import { bootstrapApplication } from '@angular/platform-browser';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
{{ ... }}
show = true;
toggle() { this.show = !this.show; }
}
bootstrapApplication(App);
<app-root></app-root>
Example explained
- Toggle: The button flips
showto add/remove the child. - Hooks in action: Creating the child runs
ngOnInit; removing it runsngOnDestroy. - Cleanup: Clearing the interval prevents background work after destroy.
Notes:
- Cleanup required: Clear intervals/timeouts and unsubscribe in
ngOnDestroy; Use theasyncpipe when possible. - Heavy work in hooks: Avoid expensive work in frequently called hooks (e.g.,
ngOnChanges); debounce/throttle or defer to services. - Manual listeners: Remove event listeners you add manually on destroy, or keep the cleanup function returned by
Renderer2.
Example
import { bootstrapApplication } from '@angular/platform-browser';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
{{ ... }}
export class App {
text = '';
}
bootstrapApplication(App);
<app-root></app-root>
Example explained
- Parent → Child: The input box updates
textin the parent; the child receives it via[text]. - Change record: The child stores the last prev and curr values from
SimpleChangesfor display. - Edge cases: Handles transitions like
undefined → valueorvalue → ''.
Notes:
- Immutable inputs: Replace arrays/objects instead of mutating to ensure
OnChangesruns. - With OnPush: Input reference changes trigger checks; in-place mutation may not—emit new references from parents.
- Inspect changes: Use
SimpleChangesto handle edge cases (e.g., undefined → value).
@ViewChild('box') box!: ElementRef<HTMLInputElement>;
ngAfterViewInit() { this.box.nativeElement.focus(); }
Example explained
@Input(): The child declares an inputtextthat parents can bind to.ngOnChanges(changes): ReceivesSimpleChangeswithpreviousValueandcurrentValuefor each changed input.- Immutable updates: Prefer replacing references over mutating in place to trigger change detection.
Example
import { bootstrapApplication } from '@angular/platform-browser';
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { CommonModule } from '@angular/common';
{{ ... }}
bootstrapApplication(App);
<app-root></app-root>
Example explained
- Multiple refs: Reads both the input
boxand thepanelcontainer via@ViewChild. - Defer DOM work: Uses
setTimeoutinngAfterViewInitto let the view settle before measuring. - measure(): Reads bounding box and formats a size string.
Notes:
- Don't use DOM in constructor: The view isn't ready; do DOM operations after
ngAfterViewInit. - Reading too early:
@ViewChildisundefinedbeforengAfterViewInit—check for existence or defer work.
AfterViewInit & Cleanup
Access template refs after the view initializes and clean up resources when the component is destroyed.
// Example teardown pattern
sub?.unsubscribe?.();
clearInterval(intervalId);
removeListener?.();
Example explained
- Teardown: Unsubscribe, clear intervals, and remove listeners in
ngOnDestroy. - Safety: Optional chaining (
?.) guards against missing handles.
Notes:
- Focus and measure safely: Run DOM reads/writes after
ngAfterViewInit(or insidesetTimeoutto let the view settle). - Observers & listeners: Disconnect
ResizeObserver/MutationObserverand remove manual event listeners inngOnDestroy. - Subscriptions: Use the
asyncpipe; if you subscribe manually, unsubscribe on destroy (e.g.,takeUntilDestroyed).