不破坏AoT的情况下动态加载组件 - Angular2

4

我正在尝试创建一个模块,它可以动态加载一堆组件,但不会干扰AoT。这是一个挑战,但我已经非常接近了,除了一件事情。如何检索存储在ComponentFactory中的所有组件?

在我的app.module.ts中,我将一堆组件数组传递给我的动态加载模块的forRoot():

imports: [
  DynamicLoadModule.forRoot(dynamicComponents),
]

在我的dynamic-load.module.ts文件中,我将所有组件添加到了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)
            }]
        };
    }

现在问题出现在DynamicLoadService中,这个服务与AoT冲突。我已经尝试了文档中提到的导出函数的方式,但是这并没有解决问题,因为这种方式我无法将components作为参数传递给服务。因此,在Angular文档中找到的以下内容并不能解决我的问题:
let heroServiceFactory = (logger: Logger, userService: UserService) => {
  return new HeroService(logger, userService.user.isAuthorized);
};

export let heroServiceProvider =
  { provide: HeroService,
    useFactory: heroServiceFactory,
    deps: [Logger, UserService]
  };

于是我尝试通过使用OpaqueToken将组件传递给我的dynamic-load.module,但这也没有帮助,因为最好情况下我只有未编译的组件,而且我的模块失去了很多灵活性。

所以我得出结论,如果我需要一个包含所有ComponentFactory中组件的数组,我只需要找到一种检索它们的方法。
现在,我使用ComponentFactoryResolver根据名称获取一个模板,但我需要获取它们所有的名称,或者至少获取工厂中所有组件的名称。

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;
}
1个回答

3

编辑 所以第一个答案并没有完全解决问题,但是另一位热心的人通过Angular Github帮助我解决了这个问题。

最终我的代码如下:

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')]]
            }]
        };
    }
}

正如某人指出的那样,ANALYZE_FOR_ENTRY_COMPONENTS不是依赖注入树的一部分(在此处找到源代码:here)。因此上述解决方法解决了这个问题。
所以一个非常乐于助人的人在 Angular Github 上向我展示了答案。
他建议我只需将 ANALYZE_FOR_ENTRY_COMPONENTS 注入到 DynamicLoadService 中即可。现在看起来像这样:
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)]
            }]
        };
    }
}

在Github上查看源代码


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接