Angular 2:要使用另一个组件的静态 <td> 和动态 <td> 渲染 table 的组件

Angular 2: Component to render table with static <td>s and dynamic <td>s from another component

我有一个 Angular 2 组件,它用小猫对象数据渲染了一个很好的 table。

由于 一些 的列将在不同的组件中重复使用,我正在寻找一种方法将 <td> 提取到一个单独的组件中( dynamic-kitten-tds)。我无法移动呈现 kitten.namekitten.lastWashed<td>s,因为它们对于 cat-o-base 组件是唯一的:

cat-o-base.component.html

<table>
<tbody>
    <tr *ngFor="let kitten of kittenBasket">
        <td>{{ kitten.name }}</td>

        <dynamic-kitten-tds [value]="kitten"></dynamic-kitten-tds>

        <td>{{ kitten.lastWashed | date }}</td>
    </tr>
</tbody>
<table>

动态小猫-tds.component.html

dynamic-kitten-tds 组件的整个模板如下所示:

<td *ngFor="let preference of kitten.preferences">{{ preference | json }}</td>

限制 1

我可能不会像这样使用*ngFor:

<td>{{ kitten.name }}</td>
<td *ngFor="let preference of kitten.preferences" [value]="preference"></td>
<td>{{ kitten.lastWashed | date }}</td>

此限制来自必须作为 dynamic-kitten-tds 组件的一部分实施的业务逻辑。

限制2

代码必须产生有效的 DOM 发射。

问题

如何实现?使用辅助组件很好。使用特殊的结构指令也可以。

P.S

我查看了其他一些 SO 问题(例如 ),但是没有找到完全匹配的问题定义。

如果使用辅助组件没问题,我的想法是:

动态-outlet.ts

@Directive({selector: '[dynamicOutlet]'})
export class DynamicOutlet implements OnChanges, OnDestroy {
  @Input() dynamicOutlet: Type<any>;
  @Input() dynamicOutletModel: any;

  private componentRef: ComponentRef<any> = null;

  constructor(private vcRef: ViewContainerRef) {}

  ngOnChanges(changes: SimpleChanges) {
    this.vcRef.clear();
    this.componentRef = null;

    if (this.dynamicOutlet) {
      const elInjector = this.vcRef.parentInjector;
      const componentFactoryResolver = elInjector.get(ComponentFactoryResolver);

      const componentFactory = componentFactoryResolver.resolveComponentFactory(this.dynamicOutlet);
      this.componentRef = componentFactory.create(elInjector);

      this.componentRef.changeDetectorRef.detectChanges();
      this.componentRef.instance.model = this.dynamicOutletModel;
      this.vcRef.createEmbeddedView(this.componentRef.instance.template, { $implicit: this.dynamicOutletModel });
    }
  }

  ngOnDestroy() {
    if(this.componentRef) {
      this.vcRef.clear();
      this.vcRef = null;
    }
  }
}

kitten.ts

@Component({
    selector: 'kitten-component',
    template: `
      <ng-template let-model>
        <td *ngFor="let preference of model.preferences">{{ preference | json }}</td>
      </ng-template>
    `
})
export class Kitten {
  @ViewChild(TemplateRef) template: TemplateRef<any>;

  model: any;
}

然后你就可以像

一样使用它了

查看

<ng-container *dynamicOutlet="kittenComp; model: kitten"></ng-container>

分量

kittenComp = Kitten;

不要忘记将 Kitten 组件添加到 entryComponents 数组。

这里是Plunker Example