Saturday, 21 September 2024

Dependency injection in Angular

Understanding dependency injection

Two main roles exist in the DI system: dependency consumer and dependency provider.

Angular facilitates the interaction between dependency consumers and dependency providers using an abstraction called Injector.

When a dependency is requested, the injector checks its registry to see if there is an instance already available there. If not, a new instance is created and stored in the registry. Angular creates an application-wide injector (also known as "root" injector) during the application bootstrap process, as well as any other injectors as needed.

Providing dependency

Imagine there is a class called HeroService that needs to act as a dependency in a component.

The first step is to add the @Injectable decorator to show that the class can be injected.

  @Injectable()
  class HeroService {}

The next step is to make it available in the DI by providing it. A dependency can be provided in multiple places:

  • At the Component level, using the providers field of the @Component decorator. In this case the HeroService becomes available to all instances of this component and other components and directives used in the template.
    For example:

  @Component({
    standalone: true,
    selector: 'hero-list',
    template: '...',
    providers: [HeroService]
  })
  class HeroListComponent {}

        When you register a provider at the component level, you get a new instance of the service
        with each new instance of that component.

  • For NgModule based applications, use the providers field of the @NgModule decorator to provide a service or other Injectable available at the application level.

for example:

  export const appConfig: ApplicationConfig = {
    //List of providers that should be available to the root component and all its children.
        providers: [
          { provide: HeroService },
        ]
    };

Then, in main.ts:

  bootstrapApplication(AppComponent, appConfig)

ApplicationConfig: Set of config options available during the application bootstrap operation.

At the application root level, which allows injecting it into other classes in the application. This can be done by adding the providedIn: 'root' field to the @Injectable decorator:

  @Injectable({
    providedIn: 'root'
  })
  class HeroService {}

When you provide the service at the root level, Angular creates a single, shared instance of the HeroService and injects it into any class that asks for it. Registering the provider in the @Injectable metadata also allows Angular to optimize an app by removing the service from the compiled application if it isn't used, a process known as tree-shaking.

Injecting a dependency

The most common way to inject a dependency is to declare it in a class constructor. When Angular creates a new instance of a component, directive, or pipe class, it determines which services or other dependencies that class needs by looking at the constructor parameter types. For example, if the HeroListComponent needs the HeroService, the constructor can look like this:

  @Component({ … })
  class HeroListComponent {
    constructor(private service: HeroService) {}
  }

When Angular discovers that a component depends on a service, it first checks if the injector has any existing instances of that service. If a requested service instance doesn't yet exist, the injector creates one using the registered provider, and adds it to the injector before returning the service to Angular.

When all requested services have been resolved and returned, Angular can call the component's constructor with those services as arguments.

 How Dependency Injection & Resolution Works in Angular?

The Angular creates a hierarchical dependency injection system. It creates a hierarchical tree of Injectors. Each Injector gets their own copy of Angular Providers. Together these two form the core of the Angular dependency injection framework. 

Injector

The Angular creates an Injector instance for every Component, Directive, etc it loads. It also creates an injector instance for the Root Module and for every lazy loaded module. But eagerly loaded modules do not get their own injector but share the injector of the Root Module.

Injector Tree

Angular Creates not one but two injector trees. Module Injector tree & Element Injector tree.

Module Injector tree is for Modules (@NgModule). For Root Module & for every Lazy Loaded Module.

Element Injector tree is for DOM Elements like Components & Directives.

Module Injector Tree

Angular creates the ModuleInjector for the services to be provided at Module Levels.

Angular Creates the Module Injector tree when the Application starts.

At the top of the Module Injector tree, Angular creates an instance of Null Injector. The Null Injector always throws an error unless we decorate the dependency with the Optional decorator.

Under Null Injector Angular creates an instance of PlatformInjector. Platform Injector usually includes built-in providers like DomSanitize etc.



Dependency providers
  • Class providers: useClass : The useClass provider key lets you create and return a new instance of the specified class. You can use this type of provider to substitute an alternative implementation for a common or default class. The alternative implementation can, for example, implement a different strategy, extend the default class, or emulate the behavior of the real class in a test case. In the following example, the BetterLogger class would be instantiated when the Logger dependency is requested in a component or any other class.

      [{ provide: Logger, useClass: BetterLogger }]

  • Alias providers: useExisting
  • Factory providers: useFactory

Read more in detail https://www.tektutorialshub.com/angular/angular-dependency-injection/

https://www.tektutorialshub.com/https://www.tektutorialshub.com/

https://www.tektutorialshub.com/angular/angular-providers/


0 comments:

Post a Comment

Topics

ADFS (1) ADO .Net (1) Ajax (1) Angular (47) Angular Js (15) ASP .Net (14) Authentication (4) Azure (3) Breeze.js (1) C# (49) CD (1) CI (2) CloudComputing (2) Coding (8) CQRS (1) CSS (2) Design_Pattern (7) DevOps (4) DI (3) Dotnet (10) DotnetCore (19) Entity Framework (4) ExpressJS (4) Html (4) IIS (1) Javascript (17) Jquery (8) Lamda (3) Linq (10) microservice (4) Mongodb (1) MVC (46) NodeJS (8) React (10) SDLC (1) Sql Server (32) SSIS (3) SSO (1) TypeScript (3) UI (1) UnitTest (2) WCF (14) Web Api (16) Web Service (1) XMl (1)

Dotnet Guru Archives