Saturday 21 September 2024

@Self, @SkipSelf & @Optional Decorators Angular

@Self, @SkipSelf and @Optional are Angular Decorators that configure how the DI Framework should resolve the dependencies. These decorators are called Resolution Modifiers because they modify the behavior of injectors. In this page, we will learn @Self, @SkipSelf, & @Optional. 

 How Angular DI Framework Resolves Dependencies

When a component asks for Dependency, the DI Framework resolves it in two phases.

In the first phase, it starts to look for the Dependency in the current component’s ElementInjector. If it does not provide the Dependency, it will look in the Parent Components ElementInjector. The Request bubbles up until it finds an injector that provides the service or reaches the root ElementInjector.

If ElementInjector does not satisfy the request, Angular looks for the Dependency in the ModuleInjector hierarchy. If Angular still doesn’t find the provider, it throws an error.

We have created an example project in Angular to explain the @Self, @SkipSelf, & @Optional. 

The Code contains a RandomService, which generates a Random Number when initialized. The Angular Service is added to the Providers array of the AppModule. We can inject this service anywhere in our Application.

@Injectable({
  providedIn: "root"
})
export class RandomService {

The project contains three Angular Components (AppComponent, ChildComponent & GrandChildComponent) all inject the RandomService and displays the Random Number from the Service.

We also have testDirective, which we include in the template of GrandChildComponent. It also displays the Random Number from the Service.

Ensure that the Providers array is empty in all components & directives. Run the App. Angular creates only one instance of the RandomService. That is why all the components and directives show the same number.


@Self: The @Self decorator instructs Angular to look for the dependency only in the local injector. The local injector is the injector that is part of the current component or directive.

import { ComponentSkipSelfSelfOptionalHost } from "@angular/core";
import { RandomService } from "./random-service";

@Component({
  selector: "my-grandChild",
  template: `
    <div class="box">
      GrandChildComponent => {{ randomNo }}
      <div class="dirbox" testDirective>fdf</div>
    </div>
  `,
  providers: [RandomService]
})
export class GrandChildComponent {
  randomNo;
  constructor(@Self() private randomServiceRandomService) {
    this.randomNo = randomService.RandomNo;
  }

This forces the Angular DI Framework to look for the Dependency attached to the current Component. I added the RandomService to the providers array of the GrandChildComponent.

As you can see from the image Angular creates two instances of RandomService. One from the AppModule and another from the GrandChildComponent. Also, note that testDirective picks up the RandomService provided from the GrandChildComponent and not from the AppModule

@SkipSelf: The @SkipSelf decorator instructs Angular to look for the dependency in the Parent Injector and upwards.

It tells Angular not to look for the injector in the local injector, but start from the Parent. You can think of this decorator as the opposite of the @Self

Open the GrandChildComponent again. Add the SkipSelf instead of Self decorator.

export class GrandChildComponent {
  randomNo;
  constructor(@SkipSelf() private randomServiceRandomService) {
    this.randomNo = randomService.RandomNo;
  }
}

As you can see from the image, the GrandChildComponent, picks up RandomService instance provided by the Module and not the one provided by itself. 
But, the testDirective still picks up the RandomService provided by the GrandChildComponent.

@Optional: Optional marks the dependency as Optional. If the dependency is not found, then it returns null instead of throwing an error

In the GrandChildComponent remove the RandomService from the Providers Array and add the @Self decorator. You will instantly receive the error “No provider for RandomService found in NodeInjector“.

Add the @Optional decorator along with the @Self. Now, the dependency injection will return null instead of an error.

Also, remember to add the ? in randomService?, else you will get the “Cannot read property ‘RandomNo’ of null” error.

export class GrandChildComponent {
  randomNo;
  constructor(@Optional() @Self() private randomServiceRandomService) {
    this.randomNo = randomService?.RandomNo;
  }
}

As you can see in the image, GrandChildComponent does not receive any values, while testDirective picks up the RandomService provided by the AppModule



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# (47) CD (1) CI (2) CloudComputing (2) Coding (8) CQRS (1) CSS (2) Design_Pattern (7) DevOps (4) DI (3) Dotnet (10) DotnetCore (17) Entity Framework (4) ExpressJS (4) Html (4) IIS (1) Javascript (17) Jquery (8) Lamda (3) Linq (10) microservice (3) Mongodb (1) MVC (46) NodeJS (8) React (10) SDLC (1) Sql Server (32) SSIS (3) SSO (1) TypeScript (3) UI (1) UnitTest (1) WCF (14) Web Api (16) Web Service (1) XMl (1)

Dotnet Guru Archives