> ## Content Index
> Fetch the complete content index at: https://mishelshaji.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Angular Lifecycle Events: A Beginner's Guide
- URL: https://mishelshaji.com/angular-lifecycle-events-a-beginners-guide/
- Published: 2026-08-11T10:16:53.000Z
- Updated: 2026-08-11T10:16:53.000Z
- Description: When I first started building Angular applications, one of the biggest hurdles I faced wasn't writing HTML templates or creating services—it was understanding when things actually happen inside a component.
- Author: Mishel Shaji
- Tags: Web Development, Angular

When I first started building Angular applications, one of the biggest hurdles I faced wasn't writing HTML templates or creating services—it was understanding **when** things actually happen inside a component.

Have you ever tried fetching data from an API inside a component, only to get an `undefined` error on an input property? Or tried to manipulate a DOM element before Angular finished rendering it? If so, you have bumped headfirst into the **Angular Component Lifecycle**.

Understanding lifecycle events is like learning the rhythm of Angular. Once you know which hook runs when, you stop fighting the framework and start building smooth, bug-free applications.

## What Is a Component Lifecycle?

Think of an Angular component like a living organism. It gets born (created), it grows and updates when new information comes in (change detection), and eventually, it dies (gets removed from the screen).

```
 [Born]                  [Lives & Updates]               [Destroyed]
Creation -------------> Data Changes / Rendering ------------> Cleanup
(constructor,           (ngOnChanges, ngOnInit,              (ngOnDestroy)
 ngOnInit)              ngAfterViewInit, etc.)
```

Angular gives us special built-in methods called **Lifecycle Hooks**. These hooks allow us to step in at specific moments during a component's life and run our own code.

## The Execution Order at a Glance

Before diving into each hook, here is the exact chronological order Angular follows during a component's life cycle (starting with JavaScript instantiation):

| **Order** | **Method / Hook**       | **Frequency**              | **Primary Purpose**                                  |
| --------- | ----------------------- | -------------------------- | ---------------------------------------------------- |
| **1**     | constructor()           | Once                       | Class instantiation & dependency injection.          |
| **2**     | ngOnChanges()           | Whenever @Input() changes  | Respond to updated input bindings.                   |
| **3**     | ngOnInit()              | Once                       | Initialize component logic after inputs are ready.   |
| **4**     | ngDoCheck()             | Every change detection run | Custom change detection for complex state.           |
| **5**     | ngAfterContentInit()    | Once                       | After projected content (<ng-content>) is loaded.    |
| **6**     | ngAfterContentChecked() | Every change detection run | After projected content has been checked.            |
| **7**     | ngAfterViewInit()       | Once                       | After component view & child views are fully loaded. |
| **8**     | ngAfterViewChecked()    | Every change detection run | After component view & child views are checked.      |
| **9**     | ngOnDestroy()           | Once                       | Cleanup logic right before the component dies.       |

## Deep Dive into Every Lifecycle Hook

Let me walk you through how each lifecycle hook works in code, why it exists, and when you should use it.

### 1\. The Constructor (`constructor`)

While not technically an Angular lifecycle hook (it's a standard JavaScript class constructor), it is step 1 where everything begins.

- **When it runs:** First, when JavaScript creates the component instance.
- **Best for:** Injecting services via Dependency Injection (DI).
- **Avoid:** Fetching API data or reading `@Input()` values here. Input bindings are **not** available inside the constructor yet.

```typescript
import { Component, Input } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-user-card',
  template: `<h2>{{ userTitle }}</h2>`
})
export class UserCardComponent {
  @Input() userId!: string;
  userTitle = '';

  // Good: Inject services here
  constructor(private userService: UserService) {
    // Bad: this.userId is undefined here!
    // console.log(this.userId); 
  }
}

```

### 2\. `ngOnChanges`

`ngOnChanges` is the first official Angular lifecycle hook to run if your component receives `@Input()` properties.

- **When it runs:** Before `ngOnInit()`, and every single time an `@Input()` property changes.
- **Parameter:** It provides a `SimpleChanges` object containing the previous value, current value, and whether it's the first change.
- **Best for:** Reacting instantly whenever a parent component updates a value passed down to this component.

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

@Component({
  selector: 'app-user-card',
  template: `<p>User ID: {{ userId }}</p>`
})
export class UserCardComponent implements OnChanges {
  @Input() userId!: string;

  ngOnChanges(changes: SimpleChanges): void {
    if (changes['userId']) {
      const prev = changes['userId'].previousValue;
      const current = changes['userId'].currentValue;
      console.log(`userId changed from ${prev} to ${current}`);
    }
  }
}

```

### 3\. `ngOnInit`

`ngOnInit` is the most widely used lifecycle hook in Angular development.

- **When it runs:** Exactly **once**, right after the first `ngOnChanges` run. At this point, all `@Input()` properties are fully initialized and ready to use.
- **Best for:** Fetching initial data from backend APIs, initializing complex component properties, and setting up component state.

```typescript
import { Component, OnInit, Input } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-user-profile',
  template: `<div *ngIf="userData">{{ userData.name }}</div>`
})
export class UserProfileComponent implements OnInit {
  @Input() userId!: string;
  userData: any;

  constructor(private userService: UserService) {}

  ngOnInit(): void {
    // Perfect place to fetch data!
    this.userService.getUser(this.userId).subscribe(data => {
      this.userData = data;
    });
  }
}

```

### 4\. `ngDoCheck`

`ngDoCheck` gives you access to Angular's internal change detection engine.

- **When it runs:** On **every single** change detection run—whenever a button is clicked, a timer fires, or an HTTP request completes.
- **Best for:** Custom change detection when Angular's automatic change detection misses something (e.g., deep mutations inside complex objects or arrays).
- **Warning:** Code placed here executes constantly. Keep logic minimal to avoid severe performance issues.

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

@Component({
  selector: 'app-item-list',
  template: `<p>Total items: {{ items.length }}</p>`
})
export class ItemListComponent implements DoCheck {
  @Input() items: string[] = [];
  private previousLength = 0;

  ngDoCheck(): void {
    // Detect array mutations that change length without changing reference
    if (this.items.length !== this.previousLength) {
      console.log('Array length changed!');
      this.previousLength = this.items.length;
    }
  }
}

```

### 5 & 6\. `ngAfterContentInit` and `ngAfterContentChecked`

These hooks deal with **Content Projection** (using `<ng-content>` to insert external HTML or components inside your component).

- **`ngAfterContentInit`**: Fires **once** after Angular projects external content into the component. Use it when you need to access elements marked with `@ContentChild` or `@ContentChildren`.
- **`ngAfterContentChecked`**: Fires after every change detection cycle that checks projected content.

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

@Component({
  selector: 'app-card',
  template: `
    <div class="card-header">
      <ng-content select="header"></ng-content>
    </div>
  `
})
export class CardComponent implements AfterContentInit {
  @ContentChild('headerText') headerEl!: ElementRef;

  ngAfterContentInit(): void {
    // Access projected header elements safely
    console.log('Projected header content:', this.headerEl.nativeElement.innerText);
  }
}

```

### 7 & 8\. `ngAfterViewInit` and `ngAfterViewChecked`

These hooks fire after Angular has finished rendering the component's HTML template and all of its child components.

- **`ngAfterViewInit`**: Fires **once** after the template view and child views are fully initialized. This is the first moment you can safely access DOM elements using `@ViewChild` or `@ViewChildren`.
- **`ngAfterViewChecked`**: Fires after every change detection check of the view.

```typescript
import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-custom-input',
  template: `<input #searchBox type="text" placeholder="Search..." />`
})
export class CustomInputComponent implements AfterViewInit {
  @ViewChild('searchBox') searchInput!: ElementRef;

  ngAfterViewInit(): void {
    // Focus the input element as soon as the view is ready
    this.searchInput.nativeElement.focus();
  }
}

```

> **Developer Pro-Tip:** Do not update component state variables inside `ngAfterViewInit` without wrapping them in `setTimeout()` or triggering a manual change detection, or you will trigger Angular's notorious `ExpressionChangedAfterItHasBeenCheckedError`.

### 9\. `ngOnDestroy` (and Modern `DestroyRef`)

`ngOnDestroy` is your cleanup worker.

- **When it runs:** Right before Angular destroys the component and removes its DOM elements.
- **Best for:** Unsubscribing from RxJS Observables, clearing `setInterval` / `setTimeout` timers, and detaching event listeners to avoid **memory leaks**.

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

@Component({
  selector: 'app-timer',
  template: `<p>Timer running...</p>`
})
export class TimerComponent implements OnInit, OnDestroy {
  private timerSub!: Subscription;

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

  ngOnDestroy(): void {
    // Always clean up subscriptions to prevent memory leaks!
    this.timerSub.unsubscribe();
    console.log('Component destroyed, subscription cleaned up.');
  }
}

```

#### Modern Alternative: `DestroyRef` and `takeUntilDestroyed`

In modern Angular, you can avoid writing boilerplate `ngOnDestroy` methods by using `DestroyRef` or the RxJS operator `takeUntilDestroyed`:

```typescript
import { Component, inject } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { interval } from 'rxjs';

@Component({
  selector: 'app-timer',
  template: `<p>Modern Clean Timer</p>`
})
export class ModernTimerComponent {
  constructor() {
    // Automatically unsubscribes when the component is destroyed!
    interval(1000)
      .pipe(takeUntilDestroyed())
      .subscribe(val => console.log(val));
  }
}

```

## Modern SSR-Safe Hooks: `afterNextRender` and `afterRender`

With modern Angular support for Server-Side Rendering (SSR), traditional hooks like `ngAfterViewInit` sometimes cause issues because they execute on both the server and the browser.

Angular introduced two modern lifecycle functions designed specifically for safe browser DOM operations:

1. **`afterNextRender`**: Runs **once** in the browser after the next change detection cycle. Ideal for initializing third-party browser-only libraries (e.g., Chart.js, Leaflet maps, D3).
2. **`afterRender`**: Runs **after every render cycle** in the browser. Useful for re-synchronizing custom canvas elements or third-party DOM components.

```typescript
import { Component, ElementRef, ViewChild, afterNextRender } from '@angular/core';

@Component({
  selector: 'app-chart',
  template: `<canvas #chartCanvas></canvas>`
})
export class ChartComponent {
  @ViewChild('chartCanvas') canvas!: ElementRef;

  constructor() {
    // Only runs in the browser, perfectly safe for SSR!
    afterNextRender(() => {
      // Initialize browser-only library here safely
      console.log('Canvas element is safe to manipulate:', this.canvas.nativeElement);
    });
  }
}

```

## 3 Common Mistakes Beginners Make

1. **Putting API calls inside `constructor()` instead of `ngOnInit()`**:
  - *Problem:* Inputs aren't ready yet, and testing becomes harder.
  - *Fix:* Keep constructors lean (for dependency injection only) and move fetch calls to `ngOnInit()`.
2. **Forgetting to unsubscribe in `ngOnDestroy()`**:
  - *Problem:* Long-running RxJS subscriptions remain active in memory long after the user leaves the page.
  - *Fix:* Use `takeUntilDestroyed()` or explicitly unsubscribe in `ngOnDestroy()`.
3. **Accessing `@ViewChild` before `ngAfterViewInit()`**:
  - *Problem:* Trying to read `@ViewChild` inside `ngOnInit()` returns `undefined` because the view hasn't finished rendering yet.
  - *Fix:* Always wait until `ngAfterViewInit()` (or `afterNextRender()`) to manipulate view elements.

Mastering these lifecycle events gives you predictable control over your Angular apps. Start simple: rely on `ngOnInit` for initialization, `ngOnChanges` for input tracking, `ngAfterViewInit` for DOM access, and `ngOnDestroy` for cleanup. As you build more complex features, the remaining hooks will fall naturally into place.