Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 4: When and why is @Inject is used in constructor?

Problem Statment

I am learning Angular 4 and I have stumble upon a code where @Inject is being used in a constructor and I am not able to figure out why...

Code and Source

I am using Angular 4 Material

Code Source: https://material.angular.io/components/dialog/overview

In the code, they are injecting MAT_DIALOG_DATA

constructor(public dialogRef: MatDialogRef<DialogOverviewExampleDialog>,
             @Inject(MAT_DIALOG_DATA) public data: any
           ) { }

Can anyone please elaborate what does it mean and when/where should we do this?

like image 884
Vikas Bansal Avatar asked Nov 01 '17 07:11

Vikas Bansal


People also ask

What is @inject in constructor Angular?

@Inject() is a manual mechanism for letting Angular know that a parameter must be injected. It can be used like so: import { Component, Inject } from '@angular/core'; import { ChatWidget } from '../components/chat-widget'; ​

What is the purpose of @inject in Angular?

The @Injectable() decorator defines a class as a service in Angular and allows Angular to inject it into a component as a dependency. Likewise, the @Injectable() decorator indicates that a component, class, pipe, or NgModule has a dependency on a service.

What does @inject constructor mean?

Definition. Constructor Injection is the act of statically defining the list of required Dependencies by specifying them as parameters to the class's constructor. The constructor signature is compiled with the type and it's available for all to see.

What is the purpose of the @inject decorator?

@inject is a decorator to annotate class properties or constructor arguments for automatic injection by LoopBack's IoC container. The injected values are applied to a constructed instance, so it can only be used on non-static properties or constructor parameters of a Class.


3 Answers

@Inject() is a manual mechanism for letting Angular know that a parameter must be injected.

import { Component, Inject } from '@angular/core';
import { ChatWidget } from '../components/chat-widget';

@Component({
  selector: 'app-root',
  template: `Encryption: {{ encryption }}`
})
export class AppComponent {
  encryption = this.chatWidget.chatSocket.encryption;

  constructor(@Inject(ChatWidget) private chatWidget) { }
}

In the above we've asked for chatWidget to be the singleton Angular associates with the class symbol ChatWidget by calling @Inject(ChatWidget). It's important to note that we're using ChatWidget for its typings and as a reference to its singleton. We are not using ChatWidget to instantiate anything, Angular does that for us behind the scenes

From https://angular-2-training-book.rangle.io/handout/di/angular2/inject_and_injectable.html

like image 52
Rahul Singh Avatar answered Oct 11 '22 16:10

Rahul Singh


If MAT_DIALOG_DATA is a non-factory/class dependency (like string for your configs), you usually use @Inject.

Also check InjectionToken: https://angular.io/guide/dependency-injection#injectiontoken

One solution to choosing a provider token for non-class dependencies is to define and use an InjectionToken


Here's a plunker: http://plnkr.co/edit/GAsVdGfeRpASiBEy66Pu?p=preview

if you remove @Inject in these cases you will receive a

Can't resolve all parameters for ComponentName: (?)

like image 38
eko Avatar answered Oct 11 '22 18:10

eko


IoC container in Angular uses the type declarations in the constructor to determine the objects to be injected to the constructor parameters.

In your example, "public data: any" parameter could not be determined by its type declaration because it's defined as "any". In order to solve this problem, you have to use "@Inject(MAT_DIALOG_DATA)" decorator to inform the IoC container about the object that must be injected to "data" parameter.

Also in your example, "@Inject" decorator is used with an InjectionToken to complicate things a little more :)

An InjectionToken is actually a class which is used to name the objects to be used by IoC container to inject in to other classes. Normally you could use any classes name as a token for IoC injection (like "MatDialogRef<DialogOverviewExampleDialog>" in your example) and this works fine. But when you start writing your UnitTests you realize that you need to use Mock objects instead of real objects to be injected into your classes and when you use real class names as your tokens, you could not do that.

To solve this problem you could use Interfaces as token names and this is actually the right solution, but since JavaScript does not support interfaces you could not use Interface names as tokens, because transpiled code does not contain Interface definitions.

As a result of all this, you need to use InjectionToken. An InjectionToken allows you to inject any object into your constructor. You just need to declare it in your modules and map to the real class that you want to be injected. This way you could use different classes for your production and test codes.

like image 9
Yildiray Meric Avatar answered Oct 11 '22 16:10

Yildiray Meric