Is it possible to list array of component dependency injectors?

angular dependency injection
angular injection token
angular pass service to child component
dependency injection system
angular inject interface
angular 9 dependency injection
angular service constructor parameters
angular inject parent component

How do I list all the dependency injectors of a component in angular?

This requirement is for unit testing.

I have an instance of a component created as follows :

component = fixture.componentInstance();

So in my test case, I need something like

console.log(component.constructor.params) // should print all the constructor parameteres

For ex in the below code :

constructor(private _logger: LoggerService, private _router: Router,
                private _adminService: AdminService) {
}

I need to fetch array of DI's

0 -> LoggerService
1 -> Router
2 -> AdminService

You should be able to take advantage of Javascript's built in arguments object.

So if you just need the names of the classes of each dependency, you can put this in your constructor:

constructor(
    private _logger: LoggerService, 
    private _router: Router,
    private _adminService: AdminService
) {
    let dependencies = Array.from(arguments).map((item) => item.constructor.name);
}

Logging the dependencies object to the console should output:

0: "LoggerService"
1: "Router"
2: "AdminService"

If your array needs to contain the full object instead of the name of the class, just remove the .map() function from the constructor code.

Dependency injection and Service Containers, Is the passing of a dependency to the dependent object? Therefore, I created a few videos about Dependency Injection on my YouTube channel. Anyway, Dependency Injection frameworks are still around in 2019. There is no overview about the current state of Dependency Injection frameworks available on the internet. Therefore, I decided to create a list as a reference.

You could monkey patch your constructor before the dependency injection:

function keepConstructorDependenciesOf(MyClass) {
  // keep references to your class and your constructor
  const originalPrototype = MyClass.prototype;
  const originalConstructor = MyClass;

  // add the logic to retrieve the type of dependencies 
  MyClass = function() { 
    this.dependencies = Array.from(arguments).map(a => a.constructor.name); 
    originalConstructor.apply(this, arguments)  
  }

  // re-apply the original prototype
  MyClass.prototype = originalPrototype;

  return MyClass;
}

Component = keepConstructorDependenciesOf(Component);

// run the dependency injection
...

component = fixture.componentInstance();

expect(component.dependencies).toEqual([
  'LoggerService', 
  'Router', 
  'AdminService'
])

Some references about redefining a constuctor

Dependency Injection in AngularJS with Example, Which component Cannot be injected as a dependency in AngularJS controller? Returns an array of service names which the function is requesting for injection. This API is used by the injector to determine which services need to be injected into the function when the function is invoked. There are three ways in which the function can be annotated with the needed dependencies.

Use this code to print out the constructor parameter. where you have to Provider to mention the services and router.

//import module services and router her 


 describe('MyComponent', () => {
  let _logger: LoggerService;
  let _router : Router;
  let _adminService :AdminService;
beforeEach(async(() => {

  TestBed.configureTestingModule({
    declarations: [
        MyComponent,
    ],
    imports: [ 
        CommonModule,
        FormsModule,
        HttpModule
  ],
  providers: [

  {provide:AdminService,  useValue: adminService},     
  {provide:Router, useValue:routerSpy} ,     
  {provide:LoggerService, useValue: logService } ,     

  ],
  }).compileComponents();

  fixture = TestBed.createComponent(MyComponent);
 component = fixture.componentInstance;
 _adminService = new AdminService(http);
  _logger = new LoggerService(http); 
}));  
    it('should create the app', async(() => {
      const fixture = TestBed.createComponent(MyComponent);
      component = fixture.componentInstance;
      const app = fixture.debugElement.componentInstance;
     console.log(component.constructor); 
    // should print all the constructor parameteres 
      expect(app).toBeTruthy();
    }));
}));

Dependency injection, as a service. Instead of a client specifying which service it will use, something tells the client what service to use. Injectors are inherited, which means that if a given injector can't resolve a dependency, it asks the parent injector to resolve it. A component can get services from its own injector, from the injectors of its component ancestors, from the injector of its parent NgModule, or from the root injector.

Why do we have to use @Injectable() in Angular?, The ModuleInjector can be configured in one of two ways: ModuleInjector is a flattening of all of the providers arrays which can be reached by following a non​-default location strategy by listing its provider in the providers list of the AppModule . When a component declares a dependency, Angular tries to satisfy that  Dependency injection is an important application design pattern. Angular has its own dependency injection framework, and we really can't build an Angular application without it. It's used so widely that almost everyone just calls it DI. In this chapter we'll learn what DI is and why we want it. Then we'll learn how to use it in an Angular app.

Hierarchical injectors, This section explores many of the features of dependency injection (DI) in Angular. by adding it to the providers array of the @Component() decorator of the sub-component. The use cases illustrate different ways to use the provide object literal to inherits from HeroesBaseComponent to display a sorted list of heroes. There are only three ways a component (object or function) can get a hold of its dependencies: The component can create the dependency, typically using the new operator. The component can look up the dependency, by referring to a global variable. The component can have the dependency passed to it where it is needed.

Dependency injection in action, The AngularJS injector subsystem is in charge of creating components, resolving their See Controllers below for a list of these special dependencies. The recommended way of declaring Controllers is using the array notation: To allow the minifiers to rename the function parameters and still be able to inject the right  With child injector modules, each module injector (each module) contains its own token. Each request initiated by any component declared in such modules will be marked with a particular token.

Comments
  • by testing what you refer to? Karma testing? add these into TestBed providers array?
  • Yes, karma-jasmine testing. Basically I want to check if the component injects particular service or not.
  • You should be testing behavior, not implementation, IMHO.
  • But how do I do that outside of constructor function?
  • @AmitChigadani you can just declare a property called dependencies in the class itself: dependencies = any[]; then in the constructor, set this.dependencies = instead of let dependencies =. Then you can always refer to this.dependencies whenever you need access to the array.
  • Sorry, but I don't want to make any changes to my existing code. Also In that case, I could directly add this line in my component file like this.dependencies = ['LoggerService', 'Router', 'AdminService']; because I know what are my DI's in my constructor.
  • Then you're going to need an instance of your class and iterate over all of the keys of this instance, to check if thos keys are instances of a specific class with either instanceof or constructor.name.
  • @AmitChigadani then I'm unclear what you're trying to accomplish. In your question you say, "in the below code I need to fetch array of DI's". I gave you a way to fetch the DI's in the constructor, so what else do you need? If you don't want to change your code then there is no way to access the injections from outside the class, since they are private (at least from a TypeScript point of view). trichetriche is right, you'd have to manually enumerate over the keys, and that would only work when you know exactly what you're looking for.