The essential difference between Constructor and ngOnInit in Angular

Post Editor

This article explores the difference between Constructor and ngOnInit lifecyle method in Angular. We'll explore JS/TS language nuances, the component initialization process and how both are supposed to be used.

4 min read
0 comments
post

The essential difference between Constructor and ngOnInit in Angular

This article explores the difference between Constructor and ngOnInit lifecyle method in Angular. We'll explore JS/TS language nuances, the component initialization process and how both are supposed to be used.

post
post
4 min read
0 comments
0 comments

One of the most popular Angular questions on stackoverflow is Difference between Constructor and ngOnInit with over 100k views. I gave my answer to this question there but also decided to expand on it in this article. While most answers in the thread and articles on the web focus on the difference between the usage of the two here I’d like to give a more comprehensive comparison that taps into components initialization process.

Let’s start with a most obvious difference that is related to the language itself. ngOnInit is just a method on a class which structurally is not different to any other method on a class. It’s just that Angular team decided to name it that way but it could have been any other name:

<>Copy
class MyComponent { ngOnInit() { } otherNameForNgOnInit() { } }

And it’s completely up to you if you want to implement that method or not on a component class. During compilation Angular compiler checks whether a component has this method implemented and marks the class with an appropriate flag:

<>Copy
export const enum NodeFlags { ... OnInit = 1 << 16,

This flag is then used to decide whether to call the method on a component class instance or not during change detection:

<>Copy
if (def.flags & NodeFlags.OnInit && ...) { componentClassInstance.ngOnInit(); }

A constructor in turn is a different thing. Regardless whether you implement it or not in TypeScript class it’s still will be called when creating an instance of a class. This is because a typescript class constructor is transpiled into a JavaScript constructor function:

<>Copy
class MyComponent { constructor() { console.log('Hello'); } }

transpiled into

<>Copy
function MyComponent() { console.log('Hello'); }

To create a class instance this function is called with the new operator:

<>Copy
const componentInstance = new MyComponent()

So if you omit the constructor in a class, it’s transpiled into an empty function:

<>Copy
class MyComponent { }

transpiles into an empty function

<>Copy
function MyComponent() {}

That is why I’m saying that a constructor is called regardless whether you implement it or not on a class.

There’s a huge difference between the two from the perspective of the component initialization phase. Angular bootstrap process consists of the two major stages:

  • constructing components tree
  • running change detection

And the constructor of the component is called when Angular constructs components tree. All lifecycle hooks including ngOnInit are called as part of the following change detection phase. Usually a component initialization logic requires either some DI providers or available input bindings or rendered DOM. And these are available at different stages of Angular bootstrap process.

When Angular constructs a components tree the root module injector is already configured so you can inject any global dependencies. Also, when Angular instantiates a child component class the injector for the parent component is also already set up so you can inject providers defined on the parent component including the parent component itself. A component constructor is the only method that is called in the context of the injector so if you need any dependency that’s the only place to get those dependencies. The @Input communication mechanism is processed as part of following change detection phase so input bindings are not available in constructor.

When Angular starts change detection the components tree is constructed and the constructors for all components in the tree have been called. Also at this point every component’s template nodes are added to the DOM. Here you have available all the data you may need to initialize a component — DI providers, DOM and input bindings.

You can read more about change detection in Everything you need to know about change detection in Angular and how Angular processes inputs in The mechanics of property bindings update in Angular.

Let’s demonstrate these phases with a quick example. Suppose you have the following template:

<>Copy
<my-app> <child-comp [i]='prop'>

So Angular starts bootstrapping the application. As described above it first creates classes for each component. So it calls MyAppComponent constructor. When executing a component constructor Angular resolves all dependencies that are injected into MyAppComponent constructor and provides them as parameters. It also creates a DOM node which is the host element of the my-app component. Then it proceeds to creating a host element for the child-comp and calling ChildComponent constructor. At this stage Angular is not concerned with the i input binding and any lifecycle hooks. So when this process is finished Angular ends up with the following tree of component views:

<>Copy
MyAppView - MyApp component instance - my-app host element data ChildComponentView - ChildComponent component instance - child-comp host element data

Only then Angular runs change detection and updates bindings for the my-app and calls ngOnInit on the MyAppComponent instance. Then it proceeds to updating the bindings for the child-comp and calls ngOnInit on the ChildComponent class.

You can learn more about a view that I’m referring to above in the Here is why you will not find components inside Angular.

And now let’s see the difference from the usage perspective.

Constructor
Link to this section

A class constructor in Angular is mostly used to inject dependencies. Angular calls this constructor injection pattern which is explained in details here. For a more in-depth architectural insights you can read Constructor Injection vs. Setter Injection by Miško Hevery.

However, the usage of a constructor is not limited to DI. For example, router-outlet directive of @angular/router module uses it to register itself and its location (viewContainerRef) within the router ecosystem. I described that approach in Here is how to get ViewContainerRef before @ViewChild query is evaluated.

Yet the common practice is put as little logic into constructor as possible.

NgOnInit
Link to this section

As we learnt above when Angular calls ngOnInit it has finished creating a component DOM, injected all required dependencies through constructor and processed input bindings. So here you have all the required information available which makes it a good place to perform initialization logic.

It’s a common practice to use ngOnInit to perform initialization logic even if this logic doesn’t depend on DI, DOM or input bindings.

Comments (0)

Be the first to leave a comment

Share

About the author

author_image

Max is a self-taught software engineer that believes in fundamental knowledge and hardcore learning. He’s the founder of inDepth.dev community and one of the top users on StackOverflow (70k rep).

author_image

About the author

Max Koretskyi

Max is a self-taught software engineer that believes in fundamental knowledge and hardcore learning. He’s the founder of inDepth.dev community and one of the top users on StackOverflow (70k rep).

About the author

author_image

Max is a self-taught software engineer that believes in fundamental knowledge and hardcore learning. He’s the founder of inDepth.dev community and one of the top users on StackOverflow (70k rep).

Looking for a JS job?
Job logo
PDQ team| Senior JavaScript developer (Angular/Node)

SD Solutions

Ukraine
Remote
$60k - $80k
Job logo
Senior Full-Stack Developer (Node+Angular)

A-Listware

Ukraine
Remote
$48k - $78k
Job logo
Senior Full stack (Angular+Node)

Monolith

Ukraine
Remote
$60k - $84k
Job logo
AngularJS Developer/.net Core - Remote Contract

InfoMagnus

United States
Remote
$115k - $134k
More jobs
NxAngularCli
NxAngularCli
NxAngularCli

Featured articles

Angularpost
13 September 20218 min read
Tracking user interaction area

Explore one of the most complex pieces of Taiga UI — ActiveZone directive that keeps an eye on what region user is working with. It touches on low-level native DOM events API, advanced RxJS and Dependency Injection, ShadowDOM and more!

Angularpost
13 September 20218 min read
Tracking user interaction area

Explore one of the most complex pieces of Taiga UI — ActiveZone directive that keeps an eye on what region user is working with. It touches on low-level native DOM events API, advanced RxJS and Dependency Injection, ShadowDOM and more!

Read more
AngularpostTracking user interaction area

13 September 2021

8 min read

Explore one of the most complex pieces of Taiga UI — ActiveZone directive that keeps an eye on what region user is working with. It touches on low-level native DOM events API, advanced RxJS and Dependency Injection, ShadowDOM and more!

Read more
Angularpost
7 September 202122 min read
Designing Angular architecture - Container-Presentation pattern

Designing architecture could be tricky, especially in the agile world, where requirement changes are frequent. So your design has to support that and provides extendibility without the need for serious modification. In such cases, you will find the Container-Presentation pattern instrumental.

micro frontendspost
6 September 202125 min read
Taking micro-frontends to the next level

The micro-frontends concept has been out there for quite a while. We’ve been using this architecture in Wix since around 2013, long before it was even given this name. In this article I’d like to share some of the things we did in order to evolve the concept of developing big scale micro-frontends.

micro frontendspost
6 September 202125 min read
Taking micro-frontends to the next level

The micro-frontends concept has been out there for quite a while. We’ve been using this architecture in Wix since around 2013, long before it was even given this name. In this article I’d like to share some of the things we did in order to evolve the concept of developing big scale micro-frontends.

Read more
micro frontendspostTaking micro-frontends to the next level

6 September 2021

25 min read

The micro-frontends concept has been out there for quite a while. We’ve been using this architecture in Wix since around 2013, long before it was even given this name. In this article I’d like to share some of the things we did in order to evolve the concept of developing big scale micro-frontends.

Read more