Blog

ngOnInit Example | Angular

Key Takeaways

  • ngOnInit runs once per component instance, after Angular initializes its inputs and before its own view is initialized.
  • Use it for one-time setup that depends on initial inputs, not for reacting to every input change.
  • implements OnInit is optional at runtime but gives TypeScript a lifecycle contract to check.
  • Omit an empty hook. Give subscriptions an appropriate cleanup strategy.

Angular ngOnInit is the lifecycle hook for one-time component initialization after initial input binding. It's a good place to seed local state from inputs; it isn't a guarantee that the component's DOM has finished rendering.

When Does Angular ngOnInit Run?

The constructor executes first. Angular then initializes the component's inputs; if ngOnChanges applies, its first call happens before ngOnInit. This simplified timeline shows the relevant boundaries, not every lifecycle hook:

constructor
    |
Angular initializes inputs
    |
first ngOnChanges (when applicable)
    |
ngOnInit
    |
component view initialization
    |
ngAfterViewInit

Once means once per instance. Destroying and recreating a component creates another initialization opportunity. Conditional rendering and navigation can create new instances, so this isn't a once-per-application or once-per-route guarantee.

Angular ngOnInit Example: Initialize an Editable Draft

A useful one-time initialization is seeding an editable draft from a parent input. The editor can then preserve the user's changes instead of continually copying the parent's value.

In a browser-only standalone Angular CLI project, replace src/main.ts with this example and keep <app-root></app-root> in src/index.html. It uses bootstrapApplication to start the standalone root component.

import { Component, input, signal } from '@angular/core';
import type { OnInit } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';

@Component({
  selector: 'app-home',
  standalone: true,
  template: `
    <label>
      Display name
      <input
        #nameInput
        [value]="draftName()"
        (input)="draftName.set(nameInput.value)"
      />
    </label>
    <p>Welcome, {{ draftName() || 'friend' }}!</p>
  `,
})
class HomeComponent implements OnInit {
  readonly initialName = input.required<string>();
  readonly draftName = signal('');

  ngOnInit(): void {
    this.draftName.set(this.initialName().trim());
  }
}

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [HomeComponent],
  template: '<app-home initialName="  Sam  " />',
})
class App {}

bootstrapApplication(App).catch((error: unknown) => {
  console.error(error);
});

input.required<string>() declares a required string input; calling initialName() reads it. A signal is a reactive value: draftName() reads the draft, and draftName.set(...) updates it. The template reference #nameInput lets the input event handler read the text field's value.

The first greeting is “Welcome, Sam!” because the hook trims the initialized input. Typing changes the draft without rerunning ngOnInit; later changes to initialName won't reset it. That's intentional for this editor's one-time starting value.

ngOnInit vs Constructor and Other Initialization Points

Keep the constructor focused on dependency injection—receiving services—and simple setup that doesn't depend on bound inputs. Reading a required input during construction can fail because Angular hasn't supplied its value yet.

Initialization pointUse it forImportant boundary
Constructor or field initializerObtaining dependencies and establishing simple defaults.Bound input values aren't guaranteed yet.
ngOnInitOne-time setup using initial inputs.Not a post-render hook.
ngOnChanges input handlingResponding to initial and subsequent input changes.Its initial call precedes ngOnInit.
ngAfterViewInitReading view-query results after view initialization.Not a general DOM-rendering guarantee.
afterNextRenderDOM measurements or manipulation after Angular renders.Register it in an injection context, typically the constructor.

View queries locate children in the component's template; content queries locate projected children and can be read after ngAfterContentInit. For direct DOM work, follow Angular's render-callback guidance; render callbacks don't run during server-side rendering.

For a read-only value derived from signal inputs, prefer computed over copying inputs into local state. Use ngOnChanges when you need explicit input-change handling; it supports both decorator-based and signal-based inputs.

Why Implement the Angular OnInit Interface?

Angular can call a correctly named ngOnInit method without implements OnInit. The interface declares ngOnInit(): void; implementing it lets TypeScript check that your class provides a compatible method.

For example, spelling the only lifecycle method ngOnInt, or requiring an incompatible method argument, fails that contract. This communicates intent and catches mistakes during compilation; it doesn't change runtime hook discovery or add runtime validation. If there's no initialization work, omit both the method and the interface.

HTTP Requests and Subscriptions in ngOnInit

Starting an HTTP request here makes sense when it depends on initial inputs and should start once per instance. HttpClient observables are cold: creating one doesn't send a request; subscribing sends it, and multiple subscriptions can produce multiple requests. Handle loading and error states explicitly rather than assuming initialization immediately produces data.

Not every observable needs a manual subscription in this hook:

  • For template consumption, AsyncPipe subscribes and automatically unsubscribes when the component is destroyed.
  • For manual subscriptions, takeUntilDestroyed from @angular/core/rxjs-interop can tie their lifetime to the component's destruction.

Ordinary HTTP response observables usually complete, but cleanup still matters: unsubscribing aborts an unfinished request. For resources needing explicit teardown, see the ngOnDestroy cleanup example.

ngOnInit and Angular CLI

The earlier claim that the CLI includes ngOnInit by default is outdated. The current standard CLI component template creates an empty class without OnInit or an empty hook. Add them when you have initialization logic; don't retain an empty hook for readability alone.

Common Mistakes

  • Treating the hook as a performance optimization. Once-per-instance execution doesn't make expensive setup cheap. Keep initialization focused.
  • Moving initial requests into checked hooks. ngDoCheck, ngAfterContentChecked, and ngAfterViewChecked can execute repeatedly during change detection; they aren't substitutes for one-time initialization.
  • Expecting an input-dependent load to refresh itself. If the input changes on the same instance, choose an input-change strategy rather than expecting another initialization call.

FAQ

When does ngOnInit run in Angular?

The constructor runs first. Angular then initializes the component's inputs and calls ngOnInit once per instance, before initializing that component's own view.

Does ngOnInit run again when an @Input changes?

No. Use ngOnChanges for input-change handling, or computed for values derived from signal inputs. A newly created component instance gets its own initialization call.

Do Angular components need ngOnInit or implements OnInit?

No: omit ngOnInit when there's no initialization work. If you define it, implements OnInit is optional at runtime but lets TypeScript check that the required method exists with a compatible signature.

Should HTTP requests be made in ngOnInit?

Yes, when an initial request depends on initialized inputs and should start once per instance. HttpClient observables don't send a request until subscribed to; handle loading, errors, cleanup, and later input changes explicitly.

How should subscriptions started in ngOnInit be cleaned up?

Use AsyncPipe for template consumption, or takeUntilDestroyed with a DestroyRef captured during construction for manual subscriptions. Ordinary HttpClient responses usually complete, but cleanup still cancels unfinished requests when the component is destroyed.

Further Reading

Written by Sam Erickson

Software engineer. I write every article on StackChief myself. Author of Mastering the Tech Interview. More about me