在AOT抛出时无法在延迟加载的模块中动态呈现组件,无法找到组件工厂

时间:2018-10-23 11:18:53

标签: javascript angular angular5 lazy-loading

当前行为

我将这些动态组件声明为模块中的入口组件,我也想在其中渲染它们。使用JIT可以正常工作。 我的应用程序的一部分包含以下结构:app -> home (lazy) -> contracts (lazy) -> search

因此,我将这些组件添加到了search component/route所用的模块中。当我使用AOT进行编译时,每次访问搜索路径时,应用程序都会告诉我没有组件工厂。当然,我搜索了google并找到了一些结果:

我尝试将它们添加到ANALYZE_FOR_ENTRY_COMPONENTS提供程序中,尝试在我的app.module中导入带有.forRoot()的ModuleWithProviders,并且还尝试仅在以下位置导入并声明我的动态及其所有从属组件:根模块(app.module)。一切都会导致相同的错误。

我将动态组件声明为入口组件,如下所示:

@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 { }

此模块被导入SearchModule,其中也声明了我的SearchComponent。在这个组件中,我想使用在ComponentFactoryResolver中注入的SearchComponent动态地渲染那些组件。

ngOnInit() {
    this.searchSettingsComponent = this.comparisonService.getSearchComponent(); // returns either EnergySearchSettingsComponent, DslSearchSettingsComponent or MobileSearchSettingsComponent
    let componentFactory = this.componentFactoryResolver.resolveComponentFactory(searchSettingsComponent);
    this.searchSettingsComponent = this.searchContainer.createComponent(componentFactory);
    this.searchSettingsComponent.instance.comparisonSettings = comparisonSettings;
    this.searchSettingsComponent.instance.onSave.subscribe(settings => this.saveSearchSettings(settings));
}

SearchComponentsearch路由的路由组件,这是我的contract路由的子路由,该路由被延迟加载。这又是我的家庭路线(也是延迟加载的)的子路线,属于主路线。

环境

Angular version: 5.2.4

For Tooling issues:
- Node version: 8.11.3
- Platform:  Mac

5 个答案:

答案 0 :(得分:2)

它必须非常简单。只需创建SharedModule并将所有可重用的动态组件放入其中,从SharedModule导出这些组件,然后将其Module导入所有必需项。延迟加载的模块。

由于它是直接导入到模块中的,因此在创建动态组件时必须可用。

答案 1 :(得分:0)

我觉得您的问题中没有足够的信息可以为您所面临的问题提供确切的答案。

我能够创建一个解决方案,感觉与您的设置类似,可用于解决问题或提出更尖锐的问题。

TLDR: Full GitHub repo here

我创建了一个应用程序结构,如下所示:

app/ app.module app.component /dynamic-provider --contains component that is dynamically loading other components --module is lazy loaded by dynamic-one module dynamic-loader.module slot.component /dynamic-one --contains lazy loaded module --module is lazy loaded by app module dynamic-one.module /dynamic-loader --contains a component to be dynamically loaded dynamic-provider.module one.component provider.service

app.module看起来如下

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot([
      { path: 'dynamic-loader', loadChildren: './dynamic-one/dynamic-one.module#DynamicOneModule' },
      { path: '', component: AppComponent }
    ])
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

dynamic-one.module外观如下

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外观如下

import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';

import { DynamicProviderModule } from '../dynamic-provider/dynamic-provider.module';

import { SlotComponent } from './slot.component';

@NgModule({
  declarations: [ SlotComponent ],
  imports: [
    DynamicProviderModule,
    RouterModule.forChild([
      { path: '', component: SlotComponent }
    ])
  ]
})
export class DynamicLoaderModule { }

dynamic-provider.module如下

import { NgModule } from '@angular/core';

import { OneComponent } from './one.component';
import { ProviderService } from './provider.service';

@NgModule({
  declarations: [ OneComponent ],
  entryComponents: [ OneComponent ],
  exports: [ OneComponent ],
  providers: [ ProviderService ]
})
export class DynamicProviderModule { }

正如您指出的那样,当模块未加载时,组件的动态创建正在工作,因此我没有在此处包含该代码(尽管出于完整性考虑,它已在回购中)。从这里可以看出,app模块延迟加载了动态一模块,而后者又延迟加载了动态加载器模块。动态加载程序模块从动态提供程序模块动态创建组件。

很难告诉您这与您的实现有何不同,因为您仅提供了少量信息。希望这可以帮助您找到想要的失物!

答案 2 :(得分:0)

您是否尝试过将angular更新到最新的6.1.10?在版本5中,我在延迟加载模块方面遇到了问题。

我有类似的任务,在6.1.4下工作正常。

我已经根据7.0.1为您创建了一个working example

我已经创建了两种情况

  1. 动态组件在模块中声明,该模块将创建动态组件
  2. 动态组件在共享模块中声明,并导入到延迟加载的模块中,这将创建动态组件。您可以为每个动态组件创建一个共享模块,因此只能在延迟加载的模块中导入一个组件

答案 3 :(得分:0)

  

创建共享模块可以组织和简化您的   码。您可以将常用的指令,管道和组件放入   一个模块,然后将其导入到您需要的任何位置   您应用的其他部分。

     

通过重新导出CommonModule和FormsModule,导入此SharedModule的任何其他模块都可以从CommonModule访问NgIf和NgFor之类的指令,并且可以使用FormsModule中的指令[[ngModel)]绑定到组件属性。

EX:

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';

import { SharedModule } from '../../shared/shared.module';
import { EntryModalComponent  } from './entry-modal.component';

@NgModule({
 imports: [
   CommonModule,
   SharedModule,
   ReactiveFormsModule
 ],
declarations: [ EntryModalComponent ],
entryComponents: [ EntryModalComponent ],
exports: [ EntryModalComponent ]
})
export class EntryModalModule { }

现在,在定义模块导入后,您可以使用EntryModalComponent在其他组件中进行动态加载。

答案 4 :(得分:0)

在最新版本中,Angular更新了许多有关延迟加载模块的人员。而且现在这个问题很可能得到解决。