【问题标题】:Angular: How to use shared modules in a Dynamic Component?Angular:如何在动态组件中使用共享模块?
【发布时间】:2018-12-26 12:35:15
【问题描述】:

我正在使用 Angular 编译器的 compileModuleAndAllComponentsAsync 在 Angular v6 中创建动态组件,下面的代码相同。

viewChangeMethod(view: string) {
    let template = `<span>${view} </span>`;
    const tmpCmp = Component({ template: template })(class { });
    this._compiler.clearCacheFor(this.tmpModule)
    this.tmpModule = NgModule({ declarations: [tmpCmp,FRAComponent],import:[ComonModule] })(class {
    });

    this._compiler.compileModuleAndAllComponentsAsync(this.tmpModule)
        .then((factories) => {
            const f = factories.componentFactories[0];
            const cmpRef = f.create(this._injector, [], null, this._m);
            this._container.detach()
            console.log(cmpRef.hostView)
            this._container.insert(cmpRef.hostView);
        })
    this._compiler.clearCacheFor(this.tmpModule)
}

一切正常,但在导入任何共享模块或自定义模块时出现错误。

【问题讨论】:

  • 我看不到您在哪里或如何尝试导入模块并使用它们 - 您可以包含该代码吗?您是否添加了imports[] 并将所需的模块添加到this.tmpModule = NgModule({ declarations: [tmpCmp] })(class { 这一行中?
  • 是的,我在 tmpModule 中导入组件和模块

标签: angular angular-components angular-compiler angular-dynamic-components


【解决方案1】:

如果您需要共享模块或任何附加模块来创建动态组件,我建议您采用稍微不同的方法来创建动态组件。

我的项目使用动态组件,并且我还将各种模块导入其中,但我使用以下方法来创建我的组件 - Full working StackBlitz

上面是我创建的 StackBlitz 示例,如果您想根据自己的需要进行调整 ||下面是代码的副本。

import {
  Component, ViewChild, AfterContentInit, ComponentFactoryResolver,
  Compiler, ViewContainerRef, NgModule, NgModuleRef
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

@Component({
  selector: 'app',
  template: '<ng-template #vc></ng-template>',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterContentInit {
  @ViewChild('vc', { read: ViewContainerRef }) _container: ViewContainerRef;
  private cmpRef;

  constructor(
    private componentFactoryResolver: ComponentFactoryResolver,
    private compiler: Compiler,
    private _m: NgModuleRef<any>) { }


  ngAfterContentInit() {
    this.addComponent();
  }

  public sayHello(): void{
    alert("Hello!");
  }

  private addComponent(): void {
    @Component({
      template: `<h2>This is a dynamic component</h2>
      <button (click)="_parent.sayHello()">Click me!</button>`
    })
    class DynamicComponent {
      constructor(public _parent: AppComponent) { }
    }
    @NgModule({
      imports: [
        BrowserModule
      ],
      declarations: [DynamicComponent],
    }) class DynamicModule { }

    const mod = this.compiler.compileModuleAndAllComponentsSync(DynamicModule);
    const factory = mod.componentFactories.find((comp) =>
      comp.componentType === DynamicComponent
    );
    this.cmpRef = this._container.createComponent(factory);
  }

}

【讨论】:

  • 您好,感谢您的代码运行良好。但是在动态组件中导入任何其他组件时,它会出错。请看我的代码stackblitz.com/edit/…
  • 啊,好吧,现在我明白发生了什么。您希望使用动态组件将另一个(静态)组件注入 DOM。我不知道任何使用动态组件来实现这一点的解决方案。对我来说,这听起来像是一个更适合 Angular Elements 的用例。 angular.io/guide/elements
【解决方案2】:

您可以按照以下解决方案完成您的工作,我已经验证了以前的 NG 版本,您可以尝试集成到您的解决方案中。

定义这样的服务

import { Injectable, Type, Component, ComponentFactoryResolver, ViewContainerRef, ComponentRef, QueryList, ComponentFactory } from '@angular/core';

@Injectable()
export class DynamicComponentService {
    constructor(private componentFactoryResolver: ComponentFactoryResolver) {
    }

    public append(componentType: Type<any>, where: ViewContainerRef): ComponentRef<any> {
        const componentFactory = this.resolveFactory(componentType);
        const componentRef = where.createComponent(componentFactory);
        return componentRef;
    }

    public resolve (componentType: Type<any>): ComponentFactory<any> {
        const componentFactory: ComponentFactory<any> = this.componentFactoryResolver.resolveComponentFactory(componentType);
        return componentFactory;
    }
}

上面的服务负责动态注入你的组件。

另请注意,您不需要将组件作为字符串传递,而需要传递其类型。

在实现之前仔细阅读上面的类。

用法——

在你的组件中注入服务 同样在组件中获取 View Container Reference(在我的 this.viewContainerReference 下面的代码中,这是必须注入动态组件的地方)

componentReference = this.dynamicComponentService.append(ComponentClass, this.viewContainerReference);
componentReference.instance.someProp = whatever;

上面的 someProp 是你的组件的公共属性,你可以给它传递一些数据。

您可以像往常一样将您的模块作为@NgModule 导入和组件的一部分导入 还要确保您有架构:[NO_ERRORS_SCHEMA]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-14
    • 2017-10-22
    • 1970-01-01
    • 2017-05-06
    • 2019-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多