Current behavior
I declared those dynamic ponents as entry ponents in the module where I also want to render them. With JIT it works fine.
Following structure has the part of my app I want to render them: app -> home (lazy) -> contracts (lazy) -> search
.
So I added those ponents to the module I use for the search ponent/route
. When I'm piling with AOT, everytime I visit the search route, the app tells me there is no ponent factory. Of course I searched google and found some results:
I tried adding them to the ANALYZE_FOR_ENTRY_COMPONENTS
provider, I tried to import a ModuleWithProviders with .forRoot()
in my app.module and I also tried simply importing and declaring my dynamic and all of its dependant ponents in the root module (app.module). Everything resulting in the same error.
I declare my dynamic ponents as entry ponents like so:
@NgModule({
imports: [SharedComponentsModule, FinoSchemaFormsModule, TabGroupModule, FinoInputModule],
declarations: [EnergySearchSettingsComponent, DslSearchSettingsComponent, MobileSearchSettingsComponent, ComparisonDetailSectionComponent],
entryComponents: [EnergySearchSettingsComponent, DslSearchSettingsComponent, MobileSearchSettingsComponent],
exports: [EnergySearchSettingsComponent, DslSearchSettingsComponent, MobileSearchSettingsComponent, ComparisonDetailSectionComponent],
providers: [CategoryMappingProvider]
})
export class ComparisonComponentsModule { }
This module gets imported in the SearchModule
, where also my SearchComponent
is declared. In this ponent I want to render those ponents dynamically using the ComponentFactoryResolver
I inject in the SearchComponent
.
ngOnInit() {
this.searchSettingsComponent = thisparisonService.getSearchComponent(); // returns either EnergySearchSettingsComponent, DslSearchSettingsComponent or MobileSearchSettingsComponent
let ponentFactory = thisponentFactoryResolver.resolveComponentFactory(searchSettingsComponent);
this.searchSettingsComponent = this.searchContainer.createComponent(ponentFactory);
this.searchSettingsComponent.instanceparisonSettings = parisonSettings;
this.searchSettingsComponent.instance.onSave.subscribe(settings => this.saveSearchSettings(settings));
}
The SearchComponent
is the routing ponent of the search
route, which is a child route of my contract
route, which gets lazy loaded. This again is a child route of my home route (also lazy loaded) and this belongs to the main route.
Environment
Angular version: 5.2.4
For Tooling issues:
- Node version: 8.11.3
- Platform: Mac
Current behavior
I declared those dynamic ponents as entry ponents in the module where I also want to render them. With JIT it works fine.
Following structure has the part of my app I want to render them: app -> home (lazy) -> contracts (lazy) -> search
.
So I added those ponents to the module I use for the search ponent/route
. When I'm piling with AOT, everytime I visit the search route, the app tells me there is no ponent factory. Of course I searched google and found some results:
I tried adding them to the ANALYZE_FOR_ENTRY_COMPONENTS
provider, I tried to import a ModuleWithProviders with .forRoot()
in my app.module and I also tried simply importing and declaring my dynamic and all of its dependant ponents in the root module (app.module). Everything resulting in the same error.
I declare my dynamic ponents as entry ponents like so:
@NgModule({
imports: [SharedComponentsModule, FinoSchemaFormsModule, TabGroupModule, FinoInputModule],
declarations: [EnergySearchSettingsComponent, DslSearchSettingsComponent, MobileSearchSettingsComponent, ComparisonDetailSectionComponent],
entryComponents: [EnergySearchSettingsComponent, DslSearchSettingsComponent, MobileSearchSettingsComponent],
exports: [EnergySearchSettingsComponent, DslSearchSettingsComponent, MobileSearchSettingsComponent, ComparisonDetailSectionComponent],
providers: [CategoryMappingProvider]
})
export class ComparisonComponentsModule { }
This module gets imported in the SearchModule
, where also my SearchComponent
is declared. In this ponent I want to render those ponents dynamically using the ComponentFactoryResolver
I inject in the SearchComponent
.
ngOnInit() {
this.searchSettingsComponent = this.parisonService.getSearchComponent(); // returns either EnergySearchSettingsComponent, DslSearchSettingsComponent or MobileSearchSettingsComponent
let ponentFactory = this.ponentFactoryResolver.resolveComponentFactory(searchSettingsComponent);
this.searchSettingsComponent = this.searchContainer.createComponent(ponentFactory);
this.searchSettingsComponent.instance.parisonSettings = parisonSettings;
this.searchSettingsComponent.instance.onSave.subscribe(settings => this.saveSearchSettings(settings));
}
The SearchComponent
is the routing ponent of the search
route, which is a child route of my contract
route, which gets lazy loaded. This again is a child route of my home route (also lazy loaded) and this belongs to the main route.
Environment
Angular version: 5.2.4
For Tooling issues:
- Node version: 8.11.3
- Platform: Mac
Share
Improve this question
edited Oct 23, 2018 at 16:52
Florian Gl
asked Oct 23, 2018 at 11:18
Florian GlFlorian Gl
6,0142 gold badges18 silver badges30 bronze badges
4
- This happened to me as well, but when i imported my dynamic ponents in app.module and add those to entryComponent, instead of feature module it just resolved... – Suryan Commented Oct 23, 2018 at 12:04
- Yeah I already tried this, but did not work unfortunately. But to be honest, this cant be the correct solution since angular's modules lose their purpose by doing this. – Florian Gl Commented Oct 23, 2018 at 12:09
- That's why it is in the ment not in the answer section :) – Suryan Commented Oct 23, 2018 at 12:13
- Can you please provide a minimum reproduction using stackblitz. – Sachin Gupta Commented Nov 1, 2018 at 11:53
5 Answers
Reset to default 3 +75It must be pretty simple. Just create the SharedModule
and put all reusable dynamic ponent in it, export those ponents from SharedModule and import this Module
in all required. Lazy loaded Modules.
Since it is imported direct to the Module, it must be available while creating the Dynamic Component.
Have you tried updating angular to latest 6.1.10? With version 5 I had issues with lazy loaded modules.
I had a similar task, and it worked fine under 6.1.4.
I've created a working example for you under 7.0.1
I've created both cases
- Dynamic ponent is declared in the module which will create the dynamic ponent
- Dynamic ponent is declared in a shared module and imported in the lazy-loaded module which will create dynamic ponents. You can create a shared module for every dynamic ponent, so you import only one ponent in a lazy loaded module
I don't feel as though there is enough information in your question to give you the exact answer to the problem you are facing.
I was able to create a solution with, what I feel is a similar setup to yours that you could use to solve your problem or to ask a more pointed question.
TLDR: Full GitHub repo here
I created an app structure as follows:
app/
app.module
app.ponent
/dynamic-provider --contains ponent that is dynamically loading other ponents
--module is lazy loaded by dynamic-one module
dynamic-loader.module
slot.ponent
/dynamic-one --contains lazy loaded module
--module is lazy loaded by app module
dynamic-one.module
/dynamic-loader --contains a ponent to be dynamically loaded
dynamic-provider.module
one.ponent
provider.service
app.module looks as follows
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { AppComponent } from './app.ponent';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
RouterModule.forRoot([
{ path: 'dynamic-loader', loadChildren: './dynamic-one/dynamic-one.module#DynamicOneModule' },
{ path: '', ponent: AppComponent }
])
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
dynamic-one.module looks as follows
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
@NgModule({
imports: [
RouterModule.forChild([
{ path: '', loadChildren: '../dynamic-loader/dynamic-loader.module#DynamicLoaderModule' }
])
]
})
export class DynamicOneModule {
constructor() {
console.log('one');
}
}
dynamic-loader.module looks as follows
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { DynamicProviderModule } from '../dynamic-provider/dynamic-provider.module';
import { SlotComponent } from './slot.ponent';
@NgModule({
declarations: [ SlotComponent ],
imports: [
DynamicProviderModule,
RouterModule.forChild([
{ path: '', ponent: SlotComponent }
])
]
})
export class DynamicLoaderModule { }
dynamic-provider.module looks as follows
import { NgModule } from '@angular/core';
import { OneComponent } from './one.ponent';
import { ProviderService } from './provider.service';
@NgModule({
declarations: [ OneComponent ],
entryComponents: [ OneComponent ],
exports: [ OneComponent ],
providers: [ ProviderService ]
})
export class DynamicProviderModule { }
As you state, your dynamic creation of ponents is working when the module isn't loaded, so I haven't included that code here(though it is in the repo for pleteness). As can be seen here though, the app module lazy loads the dynamic-one module which in turn lazy loads the dynamic-loader module. The dynamic-loader module dynamically creates ponents from the dynamic-provider module.
How this differs from your implementation is very hard to tell as you have provided only a small amount of information. I hope this helps you find the missing piece you are looking for though!
Creating shared modules allows you to organize and streamline your code. You can put monly used directives, pipes, and ponents into one module and then import just that module wherever you need it in other parts of your app.
By re-exporting CommonModule and FormsModule, any other module that imports this SharedModule, gets access to directives like NgIf and NgFor from CommonModule and can bind to ponent properties with [(ngModel)], a directive in the FormsModule.
EX:
import { CommonModule } from '@angular/mon';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { SharedModule } from '../../shared/shared.module';
import { EntryModalComponent } from './entry-modal.ponent';
@NgModule({
imports: [
CommonModule,
SharedModule,
ReactiveFormsModule
],
declarations: [ EntryModalComponent ],
entryComponents: [ EntryModalComponent ],
exports: [ EntryModalComponent ]
})
export class EntryModalModule { }
Now you can use this EntryModalComponent for dynamic loading in some other ponent after importing the module where it's defined.
In the latest versions Angular has updated a lot of staff about lazy loaded modules. And with high probability this trouble is fixed now.