🅰️ Angular Q27 / 125

Explain Angular component lifecycle hooks in detail.

AI-Powered Answer ✓ Answered

Angular components have a well-defined lifecycle managed by Angular itself. Lifecycle hooks allow developers to tap into key moments during a component's creation, update, and destruction, enabling fine-grained control over component behavior.

Overview

Angular provides a set of interfaces, known as lifecycle hooks, that you can implement in your components and directives. These interfaces declare methods that Angular calls at specific points in the component's lifecycle. By implementing these methods, you can execute custom logic at the right time, such as initializing data, performing DOM manipulation, or cleaning up resources.

Core Lifecycle Hooks

ngOnChanges

Called before ngOnInit (if the component has bound inputs) and whenever one or more data-bound input properties change. It receives a SimpleChanges object containing the current and previous property values. This hook is ideal for reacting to changes in input properties and performing actions based on those changes.

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

@Component({
  selector: 'app-child',
  template: '<p>Name: {{ name }}</p>'
})
export class ChildComponent implements OnChanges {
  @Input() name: string;

  ngOnChanges(changes: SimpleChanges): void {
    if (changes['name']) {
      console.log('Name changed from', changes['name'].previousValue, 'to', changes['name'].currentValue);
    }
  }
}

ngOnInit

Called once after the first ngOnChanges. Initializes the component after Angular sets the component's input properties and checks the first content. It's the most commonly used hook for initial setup, data fetching from a service, or complex initialization logic that doesn't rely on input changes.

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

@Component({
  selector: 'app-my-component',
  template: '<p>Component initialized!</p>'
})
export class MyComponent implements OnInit {
  ngOnInit(): void {
    console.log('ngOnInit: Component has been initialized.');
    // Perform data fetching or other setup here
  }
}

ngDoCheck

Called immediately after ngOnChanges and ngOnInit, and then after every subsequent ngOnChanges. It is also called after every change detection run, even if no inputs have changed. This hook allows you to implement your own custom change detection logic or to detect changes that Angular might not catch automatically (e.g., changes within objects or arrays passed as inputs without changing their reference). Use with caution as it can impact performance if not optimized.

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

@Component({
  selector: 'app-do-check-component',
  template: '<p>DoCheck component</p>'
})
export class DoCheckComponent implements DoCheck {
  ngDoCheck(): void {
    console.log('ngDoCheck: Always checking for changes.');
    // Custom change detection logic here
  }
}

ngAfterContentInit

Called once after Angular projects external content into the component's view (content projected via <ng-content>). This hook is useful for performing initialization logic after all projected content has been initialized. It's specifically for content that is 'transcluded' into the component.

typescript
import { Component, AfterContentInit, ContentChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-content-parent',
  template: `
    <div #projectedContent>
      <ng-content></ng-content>
    </div>
  `
})
export class ContentParentComponent implements AfterContentInit {
  @ContentChild('projectedContent') projectedDiv: ElementRef;

  ngAfterContentInit(): void {
    console.log('ngAfterContentInit: Projected content initialized.', this.projectedDiv.nativeElement.textContent);
  }
}

ngAfterContentChecked

Called after every ngDoCheck and after the content of the component has been checked. This hook is useful for performing actions that need to happen after Angular has checked the projected content for changes. It's triggered frequently, so use sparingly.

typescript
import { Component, AfterContentChecked } from '@angular/core';

@Component({
  selector: 'app-content-checked-parent',
  template: `<ng-content></ng-content>`
})
export class ContentCheckedParentComponent implements AfterContentChecked {
  ngAfterContentChecked(): void {
    console.log('ngAfterContentChecked: Projected content checked.');
  }
}

ngAfterViewInit

Called once after Angular initializes the component's view and its child views. This hook is ideal for direct DOM manipulation, working with child components (using @ViewChild or @ViewChildren), or integrating third-party libraries that require access to the rendered view. It is important to note that content children are not available here, only view children.

typescript
import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
import { ChildComponent } from './child.component'; // Assuming you have a child component

@Component({
  selector: 'app-view-init-component',
  template: `
    <p #myParagraph>This is a paragraph.</p>
    <app-child-component></app-child-component>
  `
})
export class ViewInitComponent implements AfterViewInit {
  @ViewChild('myParagraph') paragraphElement: ElementRef;
  @ViewChild(ChildComponent) childComponent: ChildComponent;

  ngAfterViewInit(): void {
    console.log('ngAfterViewInit: Component view and child views initialized.');
    console.log('Paragraph text:', this.paragraphElement.nativeElement.textContent);
    // this.childComponent.someMethod(); // Uncomment if ChildComponent has such a method
  }
}

ngAfterViewChecked

Called after every ngDoCheck and after the component's view and child views have been checked. Similar to ngAfterContentChecked, but specifically for the component's own view and its children. It's suitable for performing actions that rely on the updated state of the view after every change detection cycle. Use with extreme care to avoid performance issues or infinite loops if you modify the view within this hook.

typescript
import { Component, AfterViewChecked } from '@angular/core';

@Component({
  selector: 'app-view-checked-component',
  template: `<p>View checked.</p>`
})
export class ViewCheckedComponent implements AfterViewChecked {
  ngAfterViewChecked(): void {
    console.log('ngAfterViewChecked: Component view and child views checked.');
  }
}

ngOnDestroy

Called just before Angular destroys the component. This hook is crucial for cleanup logic, such as unsubscribing from observables, detaching event handlers, or clearing intervals/timers, to prevent memory leaks and ensure resources are properly released. It's guaranteed to be called once when the component is removed from the DOM.

typescript
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription, interval } from 'rxjs';

@Component({
  selector: 'app-destroy-component',
  template: '<p>Destroy me!</p>'
})
export class DestroyComponent implements OnInit, OnDestroy {
  private intervalSubscription: Subscription;

  ngOnInit() {
    this.intervalSubscription = interval(1000).subscribe(val => console.log(val));
  }

  ngOnDestroy(): void {
    console.log('ngOnDestroy: Component is being destroyed. Cleaning up resources.');
    this.intervalSubscription.unsubscribe(); // Prevent memory leak
  }
}