【问题标题】:Dynamic component loading based on type angular基于角度类型的动态组件加载
【发布时间】:2019-07-15 05:58:15
【问题描述】:

根据类型,我想以角度渲染组件。

例如,使用下面的代码,我想动态呈现标题组件。

{
 "type": "heading-1",
 "text": "Sample Text"
}

下面是渲染动态组件的逻辑

private renderReactiveContent(content: ContentDocument, container: ViewContainerRef) {

    // resolve content['_type'] to factory
    const type: Type<any> = this.contentMappings[content[0].type];
    if (!type) {
      throw new ReferenceError(`No content mapping for type=${content[0].type}`);
    }

    const componentFactory: ComponentFactory<any> = this.componentFactoryResolver.resolveComponentFactory(type);
    const component = container.createComponent(componentFactory, container.length, this.injector);
    console.info('Component dynamically created ', component);

    // content lifecycle hook: notify of new values
    const cmpCreate: ContentOnCreate = asContentCreate(component);
    cmpCreate.contentOnCreate(content);

    // render embedded content
    if (content && Object.keys(content).length > 0) {

      const cmpEmbeddable: ContentEmbeddable = asContentEmbeddable(component);
      if (cmpEmbeddable) {

        // render in the target element of ContentEmbeddable
        const childContainer = cmpEmbeddable.contentEmbeddable();

        Object.keys(content).forEach((key: string) => {
          const value = content[key];

          // XX: recursive rendering
          if (value instanceof Array) {
            value.forEach((v: ContentDocument) => {
              this.renderReactiveContent(v, childContainer);
            });
          } else {
            this.renderReactiveContent(value, childContainer);
          }
        });

      } else {

        // fatal: embedded content must be hosted by ContentEmbeddable
        const cmpName = component.instance['constructor'].name;
        throw new TypeError([`Trying to render embedded content.`,
          `${cmpName} must implement interface ContentEmbeddable`].join(' '));

      }

    }
    component.hostView.detectChanges();
  }

我不确定我在这里做错了什么,它会引发错误

ERROR TypeError: Trying to render embedded content. HeadlineComponent must implement interface ContentEmbeddable

我已经创建了 stackblitz,供参考的项目请帮助。

https://stackblitz.com/edit/angular-7q1izn?

【问题讨论】:

    标签: angular angular-components


    【解决方案1】:

    首先,正如错误所说,您的组件必须实现接口ContentEmbeddable。您可以这样做(对于您要动态创建的每个组件):

    import { Component, OnInit, Input, ViewContainerRef, ViewChild } from '@angular/core';
    import { ContentOnCreate, ContentEmbeddable } from '../../render/content.interfaces';
    
    @Component({
      selector: 'rc-headline',
      template: `<h1>{{ text }}</h1>`
    })
    export class HeadlineComponent implements OnInit, ContentOnCreate, ContentEmbeddable {
      @Input()
      public text: string;
    
      constructor(private containerRef: ViewContainerRef) { }
    
      ngOnInit() {
      }
    
      contentOnCreate(values: { [key: string]: any; }): void {
        this.text = values.text;
      }
    
      contentEmbeddable(): ViewContainerRef {
        return this.containerRef;
      }
    
    }
    

    但是项目还是会报错:

    No content mapping for type=undefined
    

    替换这个:

    const type: Type<any> = this.contentMappings[content[0].type];
    if (!type) {
      throw new ReferenceError(`No content mapping for type=${content[0].type}`);
    }
    

    有了这个:

    var type: Type<any>;
    if (content instanceof Array) {
      type = this.contentMappings[content[0].type];
    } else {
      type = this.contentMappings[content.type];
    }
    if (!type) {
      return;
      // throw new ReferenceError(`No content mapping for type=${type}`);
    }
    

    content-host.component.ts 文件中(renderReactiveContent 方法)将修复错误,您应该会看到示例标题和呈现的三个段落。 请参阅StackBlitz 演示以及工作解决方案。

    【讨论】:

      猜你喜欢
      • 2017-07-19
      • 2022-01-04
      • 2017-10-10
      • 1970-01-01
      • 2019-07-11
      • 1970-01-01
      • 2020-12-15
      • 1970-01-01
      • 2017-11-02
      相关资源
      最近更新 更多