Lifecycle Hooks
Hook Order
Section titled “Hook Order”ngOnChanges- Input properties changengOnInit- Component initializedngDoCheck- Change detectionngAfterContentInit- Content projectedngAfterContentChecked- Content checkedngAfterViewInit- View initializedngAfterViewChecked- View checkedngOnDestroy- Before component destroyed
ngOnInit
Section titled “ngOnInit”import { Component, OnInit } from '@angular/core';
@Component({ selector: 'app-user'})export class UserComponent implements OnInit { ngOnInit() { // Initialize component // Load data, setup subscriptions this.loadUsers(); }
loadUsers() { this.userService.getUsers().subscribe(users => { this.users = users; }); }}Use for:
- Initial data loading
- Setup subscriptions
- Component initialization logic
ngOnChanges
Section titled “ngOnChanges”import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
@Component({ selector: 'app-user-detail'})export class UserDetailComponent implements OnChanges { @Input() userId!: number;
ngOnChanges(changes: SimpleChanges) { if (changes['userId']) { const current = changes['userId'].currentValue; const previous = changes['userId'].previousValue; const firstChange = changes['userId'].firstChange;
console.log(`userId changed from ${previous} to ${current}`);
if (!firstChange) { this.loadUser(current); } } }}Use for:
- React to
@Input()changes - Update derived data when inputs change
ngOnDestroy
Section titled “ngOnDestroy”import { Component, OnDestroy } from '@angular/core';import { Subject } from 'rxjs';import { takeUntil } from 'rxjs/operators';
@Component({ selector: 'app-user'})export class UserComponent implements OnDestroy { private destroy$ = new Subject<void>();
ngOnInit() { this.userService.getUsers() .pipe(takeUntil(this.destroy$)) .subscribe(users => this.users = users);
// Or manual subscription this.subscription = this.userService.getUsers().subscribe(); }
ngOnDestroy() { // Cleanup this.destroy$.next(); this.destroy$.complete();
// Or this.subscription?.unsubscribe(); }}Use for:
- Unsubscribe from observables
- Clear timers/intervals
- Remove event listeners
- Cleanup resources
ngAfterViewInit
Section titled “ngAfterViewInit”import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
@Component({ selector: 'app-input-focus', template: `<input #inputField>`})export class InputFocusComponent implements AfterViewInit { @ViewChild('inputField') inputField!: ElementRef;
ngAfterViewInit() { // View is ready, can access DOM this.inputField.nativeElement.focus(); }}Use for:
- Access
@ViewChildelements - DOM manipulation
- Initialize third-party libraries
ngAfterContentInit
Section titled “ngAfterContentInit”import { Component, ContentChild, AfterContentInit } from '@angular/core';
@Component({ selector: 'app-wrapper', template: `<ng-content></ng-content>`})export class WrapperComponent implements AfterContentInit { @ContentChild(ChildComponent) child!: ChildComponent;
ngAfterContentInit() { // Projected content is ready console.log('Child component:', this.child); }}Use for:
- Access
@ContentChildelements - Work with projected content
ngDoCheck
Section titled “ngDoCheck”import { Component, DoCheck } from '@angular/core';
@Component({ selector: 'app-custom-check'})export class CustomCheckComponent implements DoCheck { lastValue: any;
ngDoCheck() { // Called on every change detection // Use sparingly - performance impact!
if (this.value !== this.lastValue) { console.log('Value changed manually detected'); this.lastValue = this.value; } }}Use for:
- Custom change detection
- Detect changes Angular doesn’t catch
- Caution: Called very frequently
Complete Example
Section titled “Complete Example”@Component({ selector: 'app-lifecycle'})export class LifecycleComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
@Input() data: any; @ViewChild('element') element!: ElementRef;
private destroy$ = new Subject<void>();
constructor() { console.log('1. Constructor'); }
ngOnChanges(changes: SimpleChanges) { console.log('2. ngOnChanges', changes); }
ngOnInit() { console.log('3. ngOnInit'); this.loadData(); }
ngAfterViewInit() { console.log('4. ngAfterViewInit'); this.element.nativeElement.focus(); }
ngOnDestroy() { console.log('5. ngOnDestroy'); this.destroy$.next(); this.destroy$.complete(); }
private loadData() { this.service.getData() .pipe(takeUntil(this.destroy$)) .subscribe(data => this.processData(data)); }}Best Practices
Section titled “Best Practices”- Use
ngOnInitfor initialization (not constructor) - Always implement
ngOnDestroyfor cleanup - Avoid heavy logic in
ngDoCheck - Use
takeUntil()pattern for unsubscribing ngAfterViewInitfor DOM accessngOnChangesfor input-dependent logic

