Angular 2:在元素后插入模板

时间:2018-05-21 00:15:17

标签: angular

我有以下html(为了说明而简化)。

//removed irrelevant HTML
<tbody>
  <tr *ngFor="let el of elements; let i = index" >
      <td>
         <button (click)="showTemplate(i, $event)">Click me {{i}}</button>
      </td>
  </tr>
</tbody>

<template #myTemplate>
   <tr>
      <td>You have clicked a button</td>
   </tr>
</template>

我想要实现的是,当在特定tr中单击按钮时,应在特定tr之后插入模板。

我认为我能做的是使用ViewChild获取templateRef,然后获取其节点并使用类似的内容:

@ViewChild('myTemplate', {read: TemplateRef}) myTemplate;

showTemplate(i, event) { 
   // i would get selectedTR from the event
   selectedTR.insertAdjacentElement('afterend', this.myTemplate.elementRef.nativeElement)`
}

但是我在运行该函数时从this.myTemplate.elementRef.nativeElement获得的是

我遵循的方法是正确的吗?如果是,那么我的设置可能出错?如果没有,是否有更多面向角度的解决方案?

请注意我正在使用Angular 2。

2 个答案:

答案 0 :(得分:3)

虽然它没有回答关于插入模板的问题,但以下是我将如何解决您的问题:

<tbody>
    <ng-container *ngFor="let el of elements; let i = index">
        <tr>
            <td>
               <button (click)="showTemplate(el)">Click me {{i}}</button>
            </td>
        </tr>
        <tr *ngIf="el.showTemplate">
            <td>You have clicked a button</td>
        </tr>
    </ng-container>
</tbody>

TS:

showTemplate(el: any): void {
    el.showTemplate = true;
}

这实际上是与模板绑定相同的解决方案,虽然它更简单,模板HTML(在这种情况下是第二个TR)正确绑定到模型。

答案 1 :(得分:0)

如果您不想使用*ngIf并且对模板内容保持灵活性,那么动态加载组件是另一种方式。

Live example here

<强> app.component.ts

import { Component, Input, OnInit, ViewChild, ComponentFactoryResolver, OnDestroy } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
              <tbody>
                <tr *ngFor="let el of elements; let i = index" >
                    <td>
                      <row-container [element]="el"></row-container>
                    </td>
                </tr>
              </tbody>
            `
})
export class AppComponent {

  elements = [
    {id: 1, name: "Element 1", content: "This is element 1 content"},
    {id: 2, name: "Element 2", content: "This is element 2 content"},
    {id: 3, name: "Element 3", content: "This is element 3 content"},
  ];

  constructor() { }

}

<强>行container.component.ts

import { 
  Component,
  ViewContainerRef,
  Input,
  ViewChild,
  Compiler,
  NgModule,
  Injector,
  NgModuleRef
   } from '@angular/core';

export class Element {
  constructor(
    public id: number, 
    public name: string, 
    public content: string){}
}
@Component({
  selector: 'row-container',
  template: `
    <button (click)="onRowClick()">{{element.name}} </button>
    <ng-container #vc><ng-container>
  `
})
export class RowContainerComponent {

  @Input() element: Element;

  @ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;
  constructor(
    private compiler: Compiler, 
    private injector: Injector, 
    private moduleRef: NgModuleRef<any>){
  }

  onRowClick(){
    this.loadComponent();
  }

  loadComponent(){
    this.vc.detach();

    const template = "<div><span>{{name}}</span></div>";

    const tmpComp = Component({template: template})(class{});

    const tmpModule = NgModule({declarations: [tmpComp]})(class{});

    // Compile module and all components
    this.compiler.compileModuleAndAllComponentsAsync(tmpModule)
    .then((factories) =>{
        const f = factories.componentFactories[0];

        const compRef = f.create(this.injector, [], null, this.moduleRef);

        compRef.instance.name = this.element.content;

        this.vc.insert(compRef.hostView);
    });
  }

}