Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Component lifecycle

A component is created when its tag appears on the page and destroyed when the tag disappears — for example, when an @if condition becomes false. At key steps Angular calls hook methods with specific names. You put code there that must run at that moment.

The main hooks

HookWhen it is called
constructorThe object is created, inputs are not set yet
ngOnChangesAn input value changed (and before ngOnInit)
ngOnInitOnce, after the inputs are first set
ngAfterViewInitOnce, when the component's template is rendered
ngOnDestroyBefore the component is removed

You will most often need two: ngOnInit for initial loading and ngOnDestroy for cleanup.

ngOnInit

Let's load saved tasks from localStorage when the list appears on the page:

// src/app/todo-list/todo-list.ts
import { Component, OnInit, signal } from '@angular/core';
import { Todo } from '../todo';
 
@Component({
  selector: 'app-todo-list',
  templateUrl: './todo-list.html',
})
export class TodoList implements OnInit {
  todos = signal<Todo[]>([]);
 
  ngOnInit() {
    const saved = localStorage.getItem('todos');
    if (saved) {
      this.todos.set(JSON.parse(saved));
    }
  }
}

The OnInit interface is optional, but with it TypeScript checks that the method name is spelled correctly. Add a task, reload the page — the task is still there, if you added the saving effect in the signals lesson.

ngOnDestroy

Timers and subscriptions do not stop by themselves when a component is removed. Let's make a clock that shows the current time:

ng generate component clock
// src/app/clock/clock.ts
import { Component, OnDestroy, OnInit, signal } from '@angular/core';
 
@Component({
  selector: 'app-clock',
  template: `<p>It is {{ time() }}</p>`,
})
export class Clock implements OnInit, OnDestroy {
  time = signal(new Date().toLocaleTimeString());
  private timerId = 0;
 
  ngOnInit() {
    this.timerId = window.setInterval(() => {
      this.time.set(new Date().toLocaleTimeString());
    }, 1000);
  }
 
  ngOnDestroy() {
    clearInterval(this.timerId);
  }
}

Put <app-clock /> into the to-do list template and add Clock to imports — the time updates every second. When the component disappears, ngOnDestroy stops the timer.

DestroyRef

Cleanup can be described right next to the code that needs it, with inject(DestroyRef):

// src/app/clock/clock.ts
import { Component, DestroyRef, inject, signal } from '@angular/core';
 
@Component({
  selector: 'app-clock',
  template: `<p>It is {{ time() }}</p>`,
})
export class Clock {
  time = signal(new Date().toLocaleTimeString());
 
  constructor() {
    const id = setInterval(() => {
      this.time.set(new Date().toLocaleTimeString());
    }, 1000);
    inject(DestroyRef).onDestroy(() => clearInterval(id));
  }
}

The result is the same, but starting and stopping the timer sit side by side. The inject() function is covered in detail in the services lesson.

Common mistake

Reading an input in the constructor. At that moment the parent has not passed anything yet, and a required input.required() input even throws an error. Put code that needs inputs in ngOnInit or in a computed.

Thanks for reading!

Donate to the site — we work hard for you.