如何使用angular2中的组件名称动态加载组件?

Pan*_*are 16 angular

我目前正在使用以下代码在我的应用程序中动态加载角度组件.

export class WizardTabContentContainer {
  @ViewChild('target', { read: ViewContainerRef }) target: any;
  @Input() TabContent: any | string;
  cmpRef: ComponentRef<any>;
  private isViewInitialized: boolean = false;

  constructor(private componentFactoryResolver: ComponentFactoryResolver,   private compiler: Compiler) {
  }

  updateComponent() {
     if (!this.isViewInitialized) {
       return;
     }
     if (this.cmpRef) {
       this.cmpRef.destroy();
     }
     let factory = this.componentFactoryResolver.resolveComponentFactory(this.TabContent);

     this.cmpRef = this.target.createComponent(factory);
   }
}
Run Code Online (Sandbox Code Playgroud)

这里resolveComponentFactory函数接受组件类型.我的问题是,有没有办法可以使用组件名称字符串加载组件,例如我将组件定义为

export class MyComponent{
}
Run Code Online (Sandbox Code Playgroud)

如何使用组件名称字符串"MyComponent"而不是类型添加上面的组件?

yur*_*zui 37

也许这会奏效

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

@Input() comp: string;
...
const factories = Array.from(this.resolver['_factories'].keys());
const factoryClass = <Type<any>>factories.find((x: any) => x.name === this.comp);
const factory = this.resolver.resolveComponentFactory(factoryClass);
const compRef = this.vcRef.createComponent(factory);
Run Code Online (Sandbox Code Playgroud)

where this.comp是您的Component的字符串名称"MyComponent"

Plunker示例

要做到与缩小工作,请参阅

  • 谢谢.我使用factories.find解决了上述评论中的错误(x => x ['name'] === this.comp); 但是现在得到错误类型'{}'的参数不能分配给'Type <{}>'类型的参数.类型"{}"中缺少属性"apply".on line const factory = this.resolver.resolveComponentFactory(factoryClass); (2认同)
  • 我想到了.我需要添加var factoryClass = <Type <any >> factories.find((x:any)=> x.name === this.comp); Plunker的例子不同.谢谢你这种方法! (2认同)
  • 这里“this.resolver['_factories']”,“_factories”数据成员是私有的。如果我错了,请纠正我。 (2认同)
  • 使用--prod时,这似乎不起作用。有什么想法吗?所有的工厂名称都已被混淆,所有的名称都称为“ n”,因此从没有找到匹配的类型 (2认同)

小智 6

我知道这篇文章已经很旧了,但是 Angular 中的很多事情都发生了变化,而且从易用性和安全性的角度来看,我并不真正喜欢任何解决方案。这是我的解决方案,希望您更喜欢。我不会显示实例化类的代码,因为这些示例在上面,并且原始的 Stack Overflow 问题已经显示了解决方案,并且真正询问如何从选择器获取类实例。

export const ComponentLookupRegistry: Map<string, any> = new Map();

export const ComponentLookup = (key: string): any => {
    return (cls) => {
        ComponentLookupRegistry.set(key, cls);
    };
};
Run Code Online (Sandbox Code Playgroud)

将上面的 Typescript Decorator 和 Map 放入您的项目中。你可以像这样使用它:

import {ComponentLookup, ComponentLookupRegistry} from './myapp.decorators';

@ComponentLookup('MyCoolComponent')
@Component({
               selector:        'app-my-cool',
               templateUrl:     './myCool.component.html',
               changeDetection: ChangeDetectionStrategy.OnPush
           })
export class MyCoolComponent {...}
Run Code Online (Sandbox Code Playgroud)

接下来,这很重要,您需要将组件添加到entryComponents模块中。这允许在应用程序启动期间调用 Typescript Decorator。

现在,当您有类引用时,在代码中任何想要使用动态组件(如上面的几个示例)的地方,您只需从映射中获取它即可。

const classRef = ComponentLookupRegistry.get('MyCoolComponent');  
// Returns a reference to the Class registered at "MyCoolComponent
Run Code Online (Sandbox Code Playgroud)

我真的很喜欢这个解决方案,因为您注册的 KEY 可以是组件选择器,或者对您很重要或在服务器上注册的其他内容。在我们的例子中,我们需要一种方法让服务器告诉我们哪个组件(通过字符串)加载到仪表板中。