Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular - Dependency injection through @Input property

Is it a good practice to inject 'service' dependencies in @Input properties? The service in this context is not a singleton instance managed at the root level but multiple instances of different implementations of the interface.

Consider the following example: In an Angular library, the ShapeComponent has a dependency on ShapeService (interface).

Component

@Component({
  selector: 'ex-shape',
  templateUrl: '..',
})    

export class ShapeComponent {
   constructor(shapeServiceCtor: ShapeService)
    
   @Input shapeServiceInput: ShapeService;
}

A simple way to resolve the dependency is to set the input property as shown in the following code.

<ex-shape [shapeServiceInput]="rectangleShapeService" />
<ex-shape [shapeServiceInput]="ellipseShapeService" />
<ex-shape [shapeServiceInput]="polygonShapeService" />

Does the above approach hold good in resolving dependencies in Components?

If the input property approach is used then the services/dependencies have to the propagated to the child components in the same fashion. The downside of this approach is that the parent component will have to accept all the dependencies as input properties.

Are there any recommended approaches to inject and scope dependencies at the library level?

like image 501
KDR Avatar asked Jul 03 '20 14:07

KDR


2 Answers

You're not really using Angular's dependency injection at this point, which in your case I'm not sure is good or bad.

If the ShapeComponent has no way to know what instance of the service it's using, and any time you call it you need to pass an arbitrary instance, this should be ok.

If the parent of the ShapeComponent will always pass the same instance of the service, the parent could include it in its providers array and then children ShapeComponents will use that same instance.

Angular's docs have some more detailed info on the DI Hierarchy https://angular.io/guide/hierarchical-dependency-injection

Your call to constructor(shapeServiceCtor: ShapeService) will also lead to some confusion, as the component will have both the DI injected one, and another (or possibly the same) instance from the @Input

like image 96
cjd82187 Avatar answered Oct 19 '22 02:10

cjd82187


This could work in your case:

@Component({
  selector: 'ex-shape',
  templateUrl: '..',
})    
export class ShapeComponent {
   // change the type to any since any service will be comping as input
   private shapeServiceCtor: any;

   constructor(
       private injector: Injector // injector to inject incoming services
   ) {}

   // type as any
   @Input shapeServiceInput: any;

   ngOnInit() {
       // this will inject the service
       this.shapeServiceCtor = this.injector(shapeServiceInput);
   }
}
like image 31
topmoon Avatar answered Oct 19 '22 02:10

topmoon