Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injection of Generic Services in Angular

Tags:

angular

Will Angular inject more than one instance of a generic Service if it is invoked across Component constructors using different Types?

I have a lot of Services that are going to provide the same functionality for different classes that all inherit from the same base class. I'd like to use Typescript's generic pattern MyService<T extends BaseClass> to handle this.

But I don't know how it jives with Angular's injector:

  1. Will the Angular injector create more than one instance of this service if it's injected into different components with different Types?
  2. Will the injector inject the same instance if it is called with the same type?

Code:

@Injectable export class MyService<T> {     ... }  @Component export class ComponentA {     constructor(alphaService MyService<Alpha>) {}   <--Instance 1 }  @Component export class ComponentB {     constructor(betaService MyService<Beta>) {}   <----Instance 2? }  @Component export class ComponentA1 {     constructor(alphaService MyService<Alpha>) {}  <---Instance 1? } 

Is this legal? Does the injector know to create two instances of MyService?

like image 250
Daniel Patrick Avatar asked Jul 24 '16 19:07

Daniel Patrick


People also ask

What is injectable () in Angular service?

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. The injector is the main mechanism.

What are the different ways to inject the Angular service?

Constructor injection: Here, it provides the dependencies through a class constructor. Setter injection: The client uses a setter method into which the injector injects the dependency. Interface injection: The dependency provides an injector method that will inject the dependency into any client passed to it.

What is difference between @inject and @injectable in Angular?

The @Injectable decorator aims to actually set some metadata about which dependencies to inject into the constructor of the associated class. It's a class decorator that doesn't require parameters. Without this decorator no dependency will be injected...

What is injected in Angular?

The @Injectable() decorator specifies that Angular can use this class in the DI system. The metadata, providedIn: 'root' , means that the HeroService is visible throughout the application. Next, to get the hero mock data, add a getHeroes() method that returns the heroes from mock. heroes.


2 Answers

This is a simple solution:

// service and models export class User {   firstName: string }  export class Admin {   lastName: string }  @Injectable() export class GenericService<T>{   item: number = Math.random();   GetAll(): Array<T> {     let output = [];     console.log(this.item); // each instance has own value     return output;   } } 

Then set your service in module through useFactory:

providers: [   { provide: 'UserService', useFactory: () => (new GenericService<User>()) },   { provide: 'AdminService', useFactory: () => (new GenericService<Admin>()) }, ], 

and inject your service with @Inject decorator:

constructor(   @Inject('UserService') private userService: GenericService<User>,   @Inject('AdminService') private adminService: GenericService<Admin> ) { } 

Keep in mind it is better to use InjectionToken ( OpaqueToken is deprecated) for your provider token.I have used string just for simplicity.

like image 81
Himen Avatar answered Sep 20 '22 07:09

Himen


An additional instance won't be created for generics. As it is stated here, reflect-metadata (which is used by Angular 2 decorators to support TypeScript type annotations) can't obtain this kind of information:

TypeScript only emits type metadata for types available at run time, and does not emit type aliases, interfaces, or generics (as they do not have a JavaScript representation).

The amount of MyService instances depends on whether MyService was defined as component's provider or it was inherited from parent injector.

In the code above, ComponentA and ComponentA1 can inherit MyService provider from parent injector, ComponentB can get a new instance with providers: [MyService].

like image 35
Estus Flask Avatar answered Sep 20 '22 07:09

Estus Flask