【问题标题】:Recursive directives in angular 5 Dynamic modules (without circular dependencies)Angular 5 动态模块中的递归指令(无循环依赖)
【发布时间】:2018-03-05 15:29:00
【问题描述】:

我正在尝试将动态模板加载到 Angular 5 应用程序中。 首先尝试的是 Angular 文档中的示例,https://angular.io/guide/dynamic-component-loader 这是一个死胡同,因为它所做的只是动态加载静态组件。

其次是来自 AngularInDepth.com Max NgWizard K 的消息灵通的博客文章 https://blog.angularindepth.com/here-is-what-you-need-to-know-about-dynamic-components-in-angular-ac1e96167f9e

这就像动态渲染模板的魅力。但是,我在尝试连接动态组件以进行递归调用甚至加载通用模块时遇到了麻烦。

环顾 stackoverflow,大多数答案都已过时,因为 plunkers 无法正常工作,而少数有效的答案并不能真正解决循环依赖问题,甚至除了在我的情况下已经工作的插值之外加载模块。

我已经创建了一个 Angular 文档项目来演示这个问题 https://stackblitz.com/edit/angular-aa3ah1?file=src%2Fapp%2Fheroes%2Fheroes.component.ts

import { Component, OnInit, Input, ViewChild, Compiler, NgModule } from '@angular/core';
import { ViewContainerRef } from '@angular/core';
import { Portal } from './portal'
import { SharedModule } from './shared.module'
@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {

  @Input() msg: any;
  @ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;


  templates = [//interpolation works without a problem
                `<span> 
                  This works:  {{msg.comment}}
                </span>`,
                // How to import a directive in the template?
                `<span *ngFor="let comment of msg.childComments"> 
                  Directive :  {{comment.comment}}
                </span>`,
                // How to reuse the portal without circular dependancies???
                `<span> 
                  This does not work because app-heroes
                   is not accessible and importing module causes circular dependancies
                   {{msg.comment}}
                </span>
                <span *ngFor="let comment of msg.childComments">
                  <app-heroes [msg]="comment"></app-heroes>
                </span>

                `];

  constructor(private _compiler: Compiler) { }

  ngOnInit() {
    this.loadTemplate(this.templates[0], this.msg, this.vc, this._compiler);
  }

  loadTemplate(myTemplate: string, data: any, vc: ViewContainerRef, compiler: Compiler){
    const portal = Component({template: myTemplate})(Portal);
    //const pModule = NgModule({declarations: [portal], imports: [HeroesComponent]})(class{});
    const pModule = NgModule({declarations: [portal], imports: [SharedModule]})(class{});

    compiler.compileModuleAndAllComponentsAsync(pModule)
        .then((factories) => {
        const f = factories.componentFactories[0];
        const cmpRef = vc.createComponent(f);
        cmpRef.instance.msg = data;
    });
  }
}
  1. 如何让常用模块在我的动态组件(模板[1])中工作?
  2. 如何重用动态组件来制作递归指令(模板[2])?

【问题讨论】:

    标签: angular angular5


    【解决方案1】:

    如何让常用模块在我的动态组件(模板[1])中工作?

    CommonModule 包含 NgFor 指令,因此直接的方法是导入该模块:

    import { CommonModule } from '@angular/common';
    
    //...
    
    const pModule = NgModule({declarations: [portal], imports: [SharedModule, CommonModule]})(class{});
    

    但我可能会创建另一个模块,从 CommonModule 导入 NgForOf,将其添加到声明和导出数组中。稍后导入该模块,因此无需从 CommonModule 导入整个库。

    编辑:

    好的,我明白你的意思了。但是,你仍然不能在它的孩子中使用&lt;parent-comp&gt;&lt;/parent-comp&gt;,因为它会以无限循环结束。不用过多考虑重构,我可能会这样:

    通知 Portal.ts 关于评论:

    <span *ngFor="let comment of msg.childComments">
      <span msg="comment"></span>
    </span>
    // but note that msg will refer to the last item from ngFor
    

    检查它是否有任何 childComments,如果有,请通过 EventEmitter 或服务调用 HeroesComponent loadTemplate() 方法。

    【讨论】:

    • 非常感谢您..您有正确的答案先生!在 SharedModule 中导入 CommonModule 并在 SharedModule 中导出 ngForOf 的建议也很有效!(对此表示赞同)。
    • 对于第二个问题,我尝试将组件用作动态组件的加载器,在某些情况下,这些动态模板应该能够加载其他动态模板。它看起来像一个无限循环,但是在示例中使用正确的中断情况,递归循环最终结束 - 例如。如果评论有childComments,则第三个模板仅调用HeroesComponent
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-09
    • 2021-04-19
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    • 2018-07-22
    • 1970-01-01
    相关资源
    最近更新 更多