Search code examples
angulardependency-injectionangular5angular-aotangular6

angular5 dynamic component resolver


I have multiple modules, each containing various components, and a parent component that needs to contain one of these components.

Since I cannot use routes to achieve this, I authored a service that given a moduleName :string and a compomnentName : string returns the corresponding component class.

See ComponentDirectoryService in this stackblitz.

I am imitating how the router module allows feature modules to inject their own routes:

  • ComponentDirectoryModule has a forRoot and forChild methods to which a DIRECTORY_ENTRIES value is passed
  • each feature module (p1 and p2 in stackblitz) calls forChild to provide its DIRECTORY_ENTRIES
  • AppModule calls forRoot which provides ComponentDirectoryService passing in the cumulated (calls to forChild) value of DIRECTORY_ENTRIES

Everything works fine in dev mode.

In production mode everything works, but I get this scary warning:

Can't resolve all parameters for ComponentDirectoryService in ...component-directory.service.ts: (?). This will become an error in Angular v6.x

What puzzles me is that the only parameter to the service are the directory entries...

EDIT 1

Like Angular declares the ROUTES injection token:

export const ROUTES = new InjectionToken<Route[][]>('ROUTES');

so do I for DIRECTORY_ENTRIES:

export const DIRECTORY_ENTRIES = new InjectionToken<ComponentDirectoryEntry[][]>('DIRECTORY_ENTRIES');


Solution

  • The compiler misses the information about what should be actually injected into your service.

    That's why you need to explicitly use @Inject(<YOUR_INJECTION_TOKEN>) decorator to point that out:

    constructor(@Inject(DIRECTORY_ENTRIES) private entries: ComponentDirectoryEntry[]) { }
    

    This will internally set the metadata flag to the property entries and using this metadata Angular will know that DIRECTORY_ENTRIES should be injected here.