角儿童绑定和包含

时间:2018-08-01 14:25:19

标签: angular

我想用Angular做一些

<my-table-component [Items]="Items">
  <my-column-component Title="The Id">
    {{Item.Id}}
  </my-column-component>
  <my-column-component Title="The Name">
    <span>{{Item.Name}}</span>
  </my-column-component>
  <my-column-component Title="The Avatar">
    <img [src]="Item.Picture" />
  </my-column-component>
</my-table-component>

问题是我不希望现在此处立即呈现每一列的内容。

提供Items包含对象数组,例如:

Items = [
  { Id: 1, Name: "I'm One", Picture: "/picture/1.jpg" },
  { Id: 2, Name: "I'm Two", Picture: "/picture/2.jpg" },
  { Id: 3, Name: "I'm Three", Picture: "/picture/3.jpg" },
]

我想要的最终结果将是类似的

<div class="my-table-component">
  <div class="my-table-component-header">
    <div class="my-table-component-header-item">The Id</div>
    <div class="my-table-component-header-item">The Name</div>
    <div class="my-table-component-header-item">The Name</div>
  </div>
  <div class="my-table-component-content">
    <div class="my-table-component-content-item">1</div>
    <div class="my-table-component-content-item"><span>I'm One</span></div>
    <div class="my-table-component-content-item"><img [src]="/picture/1.jpg" /></div>
  </div>
  <div class="my-table-component-content">
    <div class="my-table-component-content-item">2</div>
    <div class="my-table-component-content-item"><span>I'm Two</span></div>
    <div class="my-table-component-content-item"><img [src]="/picture/2.jpg" /></div>
  </div>
  <div class="my-table-component-content">
    <div class="my-table-component-content-item">3</div>
    <div class="my-table-component-content-item"><span>I'm Three</span></div>
    <div class="my-table-component-content-item"><img [src]="/picture/3.jpg" /></div>
  </div>
</div>

因此,并不是在这里直接声明每列的绑定,而是动态地对绑定到Item的表组件的每个Items进行声明。

我已经尝试过使用NgTemplateOutlet进行操作,但是或者我不太了解它是如何工作的,或者这不是我想要的。

1 个答案:

答案 0 :(得分:1)

这是一个使用结构化指令和NgTemplateOutlet来实现所需结果的解决方案。有关完整代码,请参见此StackBlitz link

用法

启动HTML:

({app.component.html

<my-table-component [Items]="Items">
    <my-column-component>
        <my-cell *columnHeader>The Id</my-cell>
        <my-cell *columnCells="let Item">{{Item.Id}}</my-cell>
    </my-column-component>
    <my-column-component>
        <my-cell *columnHeader>The Name</my-cell>
        <my-cell *columnCells="let Item"><span>{{Item.Name}}</span></my-cell>
    </my-column-component>
    <my-column-component>
        <my-cell *columnHeader>The Avatar</my-cell>
        <my-cell *columnCells="let Item"><img src="{{Item.Picture}}" /></my-cell>
    </my-column-component>
</my-table-component>

注意:

  • 使用*columnHeader*columnCells结构化指令分别表示要成为列标题和常规表单元格的单元格

  • 要在表单元格中使用数据绑定(例如<span>{{Item.Name}}</span>),请设置*columnCells="let myVarHere"(例如*columnCells="let Item")以声明要使用的迭代变量。


最终结果:

<div class="my-table-component">
   <div class="my-table-component-header">
      <div class="my-table-component-header-item"><my-cell>The Id</my-cell></div>
      <div class="my-table-component-header-item"><my-cell>The Name</my-cell></div>
      <div class="my-table-component-header-item"><my-cell>The Avatar</my-cell></div>
   </div>
   <div class="my-table-component-content">
      <div class="my-table-component-content-item"><my-cell>1</my-cell></div>
      <div class="my-table-component-content-item"><my-cell><span>I'm One</span></my-cell></div>
      <div class="my-table-component-content-item"><my-cell><img src="/picture/1.jpg" /></my-cell></div>
   </div>
   <div class="my-table-component-content">
      <div class="my-table-component-content-item"><my-cell>2</my-cell></div>
      <div class="my-table-component-content-item"><my-cell><span>I'm Two</span></my-cell></div>
      <div class="my-table-component-content-item"><my-cell><img src="/picture/2.jpg" /></my-cell></div>
   </div>
   <div class="my-table-component-content">
      <div class="my-table-component-content-item"><my-cell>3</my-cell></div>
      <div class="my-table-component-content-item"><my-cell><span>I'm Three</span></my-cell></div>
      <div class="my-table-component-content-item"><my-cell><img src="/picture/3.jpg" /></my-cell></div>
   </div>
</div>

角度代码:

({app.component.ts

export class AppComponent {
  Items = [
    { Id: 1, Name: "I'm One", Picture: "/picture/1.jpg" },
    { Id: 2, Name: "I'm Two", Picture: "/picture/2.jpg" },
    { Id: 3, Name: "I'm Three", Picture: "/picture/3.jpg" },
  ];
}

({my-table-components.component.ts-我选择将所有与“表”相关的组件/指令放在一个文件中,但如果需要,可以将其拆分为多个文件)

import { Component, Directive, Input, TemplateRef } from '@angular/core';

@Directive({ selector: 'my-column-component' })
class MyColumnComponent { }

@Directive({ selector: 'my-cell' })
class MyCell { }

@Component({
  selector: 'my-table-component',
  template: `
  <div class="my-table-component">
    <div class="my-table-component-header">
      <div class="my-table-component-header-item" *ngFor="let header of columnHeaders">
        <ng-container *ngTemplateOutlet="header; context: {$implicit:Item}"></ng-container>
      </div>
    </div>

    <div class="my-table-component-content" *ngFor="let Item of Items">
      <div class="my-table-component-content-item" *ngFor="let cell of columnCells">
        <ng-container *ngTemplateOutlet="cell; context: {$implicit: Item}"></ng-container>
      </div>
    </div>
  </div>
  `,
  styles: []
})
class MyTableComponent {
  @Input() Items: Object[];

  columnHeaders: TemplateRef<void>[] = [];
  columnCells: TemplateRef<void>[] = [];
}


// Structural directives

@Directive({ selector: '[columnHeader]'})
class ColumnHeader {
  constructor(templateRef: TemplateRef<void>, table: MyTableComponent) {
    table.columnHeaders.push(templateRef);
  }
}

@Directive({ selector: '[columnCells]'})
class ColumnCell {
  constructor(templateRef: TemplateRef<void>, table: MyTableComponent) {
    table.columnCells.push(templateRef);
  }
}


export { MyTableComponent, MyCell, MyColumnComponent, ColumnHeader, ColumnCell }

说明

在起始HTML中,您可以使用类似的方式表示每一列:

<my-column-component>
   <my-cell *columnHeader>The Id</my-cell>
   <my-cell *columnCells="let Item">{{Item.Id}}</my-cell>
</my-column-component>

请注意,我们在*columnHeader伪指令之前加了一个星号columnCells前缀。这告诉Angular我们想将这些指令用作结构指令。 (结构指令是更改DOM 结构的指令,例如通过添加,删除或操作元素。例如,*ngIf*ngFor是结构指令。)

在内部,Angular通过将<ng-template>标签包裹在原始元素周围来消除星号语法的糖化。例如,这:

<my-cell *columnHeader>The Id</my-cell>
<my-cell *columnCells="let Item">{{Item.Id}}</my-cell>

将被转换为此:

<ng-template columnHeader>
   <my-cell>The Id</my-cell>
</ng-template>
<ng-template columnCells let-Item>
   <my-cell>{{Item.Id}}</my-cell>
</ng-template>

因此,每个带有*columnHeader*columnCells指令的元素都将被<ng-template>元素环绕。由于它们分别位于<ng-template>内,因此我们可以Angular的TemplateRef获取对<ng-template>元素的引用,然后将该引用传递到MyTableComponent中,以使用{ {1}}。

看看this diagram here,了解我的意思。

示例:

*ngTemplateOutlet

-

@Directive({ selector: '[columnCells]'})
class ColumnCell {
  constructor(templateRef: TemplateRef<void>, table: MyTableComponent) {
    table.columnCells.push(templateRef);
  }
}

我建议您看一下this excellent video,以更好地理解结构化指令和NgTemplateOutlet,以及Angular文档中的code example。NpTemplateOutlet。