Reputation: 71
So I was trying to create a module which would take a bunch of components and load them dynamically but without messing with AoT. This has proven a challenge but I'm getting really close except for one thing. How do I retrieve all the components which are stored in the ComponentFactory?
In mij app.module.ts
I pass an array of components to the forRoot() of my dynamic-load module:
imports: [
DynamicLoadModule.forRoot(dynamicComponents),
]
In my dynamic-load.module.ts
I add all of them to the Angular2 ComponentFactory:
static forRoot(components: any[]) {
return {
ngModule: DynamicLoadModule,
providers: [{
provide: ANALYZE_FOR_ENTRY_COMPONENTS,
useValue: components,
multi: true,
}, {
provide: DynamicLoadService,
useValue: new DynamicLoadService(components)
}]
};
}
Now the problem lies in the DynamicLoadService
, which is messing with AoT. I've tried the documented export-a-function way but this doesn't solve the problem because this way I'm unable to pass the components
as parameters to the service. So the following found in the Angular documentation is not providing a solution for my problem:
let heroServiceFactory = (logger: Logger, userService: UserService) => {
return new HeroService(logger, userService.user.isAuthorized);
};
export let heroServiceProvider =
{ provide: HeroService,
useFactory: heroServiceFactory,
deps: [Logger, UserService]
};
So then I tried passing the components to my dynamic-load.module
by the use of OpaqueToken
, which was also of no help because I then had uncompiled components at best and my module lost a lot of flexibilty.
So I came to the conclusion that, if I needed an array of all the components in the ComponentFactory
, I just need a way to retrieve them all.
So, where I now use the ComponentFactoryResolver
to get one template based on the name I need to get them all, or at least get all the names of the components in the factory.
if (selectedComponent !== '') {
if (typeof this.currentComponent !== 'undefined') { this.currentComponent.destroy(); }
const components = this.dynamicLoadService.getComponents(), // --> instead of getting a list of available components through this service which needs the factory that blocks AoT, I should just be able to retrieve all available components from the ComponentFactory
component: any = components.find((x) => x.name.toLowerCase().indexOf(selectedComponent) > -1),
compFactory = this.cfr.resolveComponentFactory(component);
this.currentComponent = this.vcr.createComponent(compFactory);
this.currentComponent.instance.data = this.componentData;
}
Upvotes: 4
Views: 2381
Reputation: 71
Edit So the first answer did not quite solve the problem but another helpful person was able to help me fix the problem through the Angular Github.
In the end my code looks as follows:
import { NgModule, ANALYZE_FOR_ENTRY_COMPONENTS, Inject } from '@angular/core';
import { DynamicLoadService } from './dynamic-load.service';
import { DynamicLoadComponent } from './dynamic-load.component';
export function DynamicLoadFactory(cmps) {
return new DynamicLoadService(cmps);
}
@NgModule({
declarations: [
DynamicLoadComponent
],
exports: [
DynamicLoadComponent
]
})
export class DynamicLoadModule {
static forRoot(components: any[]) {
return {
ngModule: DynamicLoadModule,
providers: [{
provide: ANALYZE_FOR_ENTRY_COMPONENTS,
useValue: components,
multi: true
},
{
provide: 'ENTRIES',
useValue: components
},
{
provide: DynamicLoadService,
useFactory: DynamicLoadFactory,
deps: [[new Inject('ENTRIES')]]
}]
};
}
}
As was pointed out to me ANALYZE_FOR_ENTRY_COMPONENTS
is not part of dependency injection tree (Find the source here). So the above workaround deals with that problem.
So the answer was presented to me be a very helpful person at the Angular Github.
It was suggested to me that I should just
Just inject
ANALYZE_FOR_ENTRY_COMPONENTS
intoDynamicLoadService
Which now looks like this:
export function DynamicLoadFactory(cmps) {
return new DynamicLoadService(cmps);
}
export class DynamicLoadModule {
static forRoot(components: any[]) {
return {
ngModule: DynamicLoadModule,
providers: [{
provide: ANALYZE_FOR_ENTRY_COMPONENTS,
useValue: components,
multi: true,
}, {
provide: DynamicLoadService,
useFactory: DynamicLoadFactory,
deps: [new Inject(ANALYZE_FOR_ENTRY_COMPONENTS)]
}]
};
}
}
Upvotes: 3