【问题标题】:Dynamically displaying elements containing HTML with (click) functions Angular 2使用(单击)功能动态显示包含 HTML 的元素 Angular 2
【发布时间】:2019-03-30 03:10:00
【问题描述】:

我有一个包含节点的递归树结构,每个节点都有一个“htmlStringContent”属性。当我使用嵌套的“节点”组件显示树并尝试呈现我使用的 html 内容时:

<div [innerHtml]="node.htmlStringContent"></div>

HTML 正确显示,但以下元素:

<a (click)="function()">click me</a>

(点击)功能不起作用。我知道这有previously been posted,但是最近 Angular 带来了大量更新,我找不到任何解决方案。 This answer 让我相信我应该使用 ngComponentOutlet 指令,但我不确定如何..

如何获得 Angular 来绑定此点击功能?

编辑:有人告诉我使用 ComponentFactoryResolver,但看不到如何使用它来正确显示 html。谁能提供进一步的帮助?

Edit2:我正在通过清理管道解析“htmlStringContent”,然后在 [innerHtml] 上显示它

transform(v: string) : SafeHtml {
  return this._sanitizer.bypassSecurityTrustHtml(v); 
} 

Edit3:基本上这个问题是询问是否尽可能在角度 2/ionic 2 中显示来自对象的属性的 HTML,同时保留其(单击)功能。我也愿意接受解决方法的答案。

【问题讨论】:

  • 这种方式点击事件不起作用。您有一个创建组件,然后您将能够生成单击事件,如您的一个链接中所示。
  • @micronyks 但我仍然必须使用 [innerHtml] 来呈现 html 内容?
  • 我明白,但是和 angular1 一样,angular2 没有$compile 服务,所以你可以使用componentFactoryResolver 来完成。
  • @micronyks 不完全确定如何使用它......你能更详细一点吗?
  • 树结构我不确定,但是当模板有角度上下文时,你应该只使用 CFR。

标签: angular typescript2.0


【解决方案1】:

CFR 演示:https://plnkr.co/edit/jKEaDz1JVFoAw0YfOXEU?p=preview

@Component({
  selector: 'my-app',
  template: `

     <button (click)="addComponents()">Add HTML (dynamically using CRF)</button>

     <h1>Angular2 AppComponent</h1>
     <hr>

     <div>
     <h5>dynamic html goes here</h5>
      <div class="container">
        <template #subContainer1></template>
      </div>
     </div>


  `,

})
export class App {
    name:string;
    @ViewChild('subContainer1', {read: ViewContainerRef}) subContainer1: ViewContainerRef;

    constructor(
      private compFactoryResolver: ComponentFactoryResolver
      ) {
      this.name = 'Angular2'
    }

    addComponents() {

      let compFactory: ComponentFactory;

      compFactory = this.compFactoryResolver.resolveComponentFactory(Part1Component);
      this.subContainer1.createComponent(compFactory);

    }
  }

【讨论】:

  • 我看到这会动态创建组件.. 但是我已经有一个使用递归 ngfor 显示的组件的嵌套结构,这个解决方案将如何呈现组件属性中包含的 html 字符串并正确呈现它,包括点击功能??
【解决方案2】:

如果我理解正确,您需要使用动态模板并在运行时编译它们。如果是这样,那么您需要使用角度编译器:

@Component({
    selector: 'my-app',
    template: `
      <h1>Angular 2 Dynamic Component</h1>
      <template #container></template>
    `
})
export class AppComponent implements AfterContentInit, OnDestroy {
  private dynamicComponentRefs: ComponentRef[] = [];

  @ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;

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

  ngAfterContentInit() {
    let html = `
      <div>Always Visible</div>
      <div [hidden]="clause1">Hidden because of clause1 = true</div>
      <div [hidden]="clause2">Visible because of clause2 = false</div>
      <button type="button" (click)="buttonClicked()">Click me!</button>
      <div *ngIf="clicked">You clicked the button!</div>
    `;

    this.compiler.compileModuleAndAllComponentsAsync(createDynamicComponent(html))
        .then((mwcf: ModuleWithComponentFactories) => {
          let factory: ComponentFactory = mwcf.componentFactories.find(cf => 
            cf.componentType.name === 'DynamicComponent');
            this.dynamicComponentRefs
              .push(this.container.createComponent(factory));
        });
  }

  ngOnDestroy() {
    /* Make sure you destroy all dynamically created components to avoid leaks */
    this.dynamicComponentRefs.forEach(dcr => {
      dcr.destroy();
    });
  }

}

export function createDynamicComponent(html: string): Type<NgModule> {
  @Component({
    template: html,
  })
  class DynamicComponent {
    private clause1: boolean = true;
    private clause2: boolean = false;
    private clicked = false;

    buttonClicked() {
      this.clicked = true;
    }
  }

  @NgModule({
    imports: [CommonModule],
    declarations: [DynamicComponent],
  })
  class DynamicComponentModule {}

  return DynamicComponentModule;
}

基本上你需要动态创建一个组件和声明它的模块(例如通过一个函数)并将模板作为参数传递给它。然后你可以在模块上调用compileModuleAndAllComponentsAsync(),获取你需要的组件工厂。然后就是通过ViewContainerRef.createComponent()方法在DOM中渲染了。

这里正在工作:dynamic template component

但请记住,目前这种方法只能用于 JIT 编译。在 AOT 编译中,角度编译器不可用,尝试使用它会引发错误。

【讨论】:

    猜你喜欢
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 2016-12-10
    • 2021-02-08
    • 2017-12-13
    • 1970-01-01
    相关资源
    最近更新 更多