重复使用动态加载的组件时出错

时间:2018-12-28 11:04:59

标签: angular typescript angular6

我已经创建了一个组件,该组件可以动态加载带有模板的子组件,该子组件是从我的服务器发出的,就像本主题一样

Compile dynamic HTML in Angular 4/5- something similar to $compile in Angular JS

我想从应用程序中的任何位置调用此组件,它的选择器可以从模式模板中调用( 我无法多次重新加载模式 ),可以从浏览器中调用( 并且我无法同时加载模式和浏览器

@Component({
  selector: 'my-component',
  template: `<h2>Stuff bellow will get dynamically created and injected<h2>
          <div #vc></div>`
})
export class TaggedDescComponent {
  @ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;

  private cmpRef: ComponentRef<any>;

  constructor(private compiler: Compiler,
              private injector: Injector,
              private moduleRef: NgModuleRef<any>,
              private backendService: backendService,
              ) {}

  ngAfterViewInit() {
    // Here, get your HTML from backend.
    this.backendService.getHTMLFromServer()
        .subscribe(rawHTML => this.createComponentFromRaw(rawHTML));
  }

  // Here we create the component.
  private createComponentFromRaw(template: string) {
    // Let's say your template looks like `<h2><some-component [data]="data"></some-component>`
    // As you see, it has an (existing) angular component `some-component` and it injects it [data]

    // Now we create a new component. It has that template, and we can even give it data.
    const tmpCmp = Component({ template, styles })(class {
      // the class is anonymous. But it's a quite regular angular class. You could add @Inputs,
      // @Outputs, inject stuff etc.
      data: { some: 'data'};
      ngOnInit() { /* do stuff here in the dynamic component */}
    });

    // Now, also create a dynamic module.
    const tmpModule = NgModule({
      imports: [RouterModule],
      declarations: [tmpCmp],
      // providers: [] - e.g. if your dynamic component needs any service, provide it here.
    })(class {});

    // Now compile this module and component, and inject it into that #vc in your current component template.
    this.compiler.compileModuleAndAllComponentsAsync(tmpModule)
      .then((factories) => {
        const f = factories.componentFactories[0];
        this.cmpRef = f.create(this.injector, [], null, this.moduleRef);
        this.cmpRef.instance.name = 'my-dynamic-component';
        this.vc.insert(this.cmpRef.hostView);
      });
  }

  // Cleanup properly. You can add more cleanup-related stuff here.
  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
  }
}

但是当重新加载此部分(不刷新浏览器)时,我出现此错误:

ERROR Error: Type e is part of the declarations of 2 modules: function(){} and function(){}! Please consider moving e to a higher module that imports function(){} and function(){}. You can also create a new NgModule that exports and includes e then import that NgModule in function(){} and function(){}.
    at le (main.js:1)
    at e._addTypeToModule (main.js:1)
    at main.js:1
    at Array.forEach (<anonymous>)
    at e.getNgModuleMetadata (main.js:1)
    at e._loadModules (main.js:1)
    at e._compileModuleAndAllComponents (main.js:1)
    at e.compileModuleAndAllComponentsAsync (main.js:1)
    at e.compileModuleAndAllComponentsAsync (main.js:1)
    at e.createComponentFromRaw (main.js:1)

1 个答案:

答案 0 :(得分:0)

因为要动态渲染的组件需要导入到组件中,并且需要在相同的组件父模块中注册。

如果要在其他应用程序中使用同一组件,则不会引起什么问题,也没有解决方法。 您可以关注以下文章,以了解更多相关信息, https://blog.angularindepth.com/here-is-what-you-need-to-know-about-dynamic-components-in-angular-ac1e96167f9e

但是过程变得非常复杂,我强烈建议您使用可以新添加到有角CDK的门户, 门户是可以动态呈现到页面上的空白位置的一部分UI。 “ UI部分”可以是Component或TemplateRef,“开放插槽”可以是PortalHost。

在同一段视频上有一个不错的演示视频。

https://www.youtube.com/watch?v=YQMIR01dQew

希望这对您有所帮助!

相关问题