(角度 2+)在 *ngFor 中使用 ng-content 无法访问循环变量



如何嵌入/投影到循环内的插槽中,并使投影内容能够访问循环变量?

假设我有一个基本组件,其中包含以下内容

<tr *ngFor="let data of items">
    <td>{{data.title}}</td>
    <ng-content select="[slot]"></ng-content>
</tr>

以及使用嵌入插槽"插槽"的子组件

<parent [items]="items"> 
    <ng-container slot>
        <td>{{data.category}}</td>
        <td>{{data.number}}</td>
    </ng-container>
</parent>

我想生成的 HTML 是

<tr>
    <td>{{data.title}}</td>
    <td>{{data.category}}</td>
    <td>{{data.number}}</td>
</tr>

但实际发生的是,子组件中没有定义"数据",这是有道理的。有什么方法可以让它像这样工作吗?

使用TemplateRef可以在模板级别以声明方式声明两个组件之间的模板变量。以下解决方案不完全匹配您的"槽"基础结构,但可能有助于进一步调查。

list.component.ts

import { Component, Input, ContentChild, TemplateRef } from '@angular/core';
@Component({
  selector: 'list',
  template: `
    <tr class="box" *ngFor="let data of items">
      <td>{{data.title}}</td>
      <ng-template
        [ngTemplateOutlet]="template"
        [ngTemplateOutletContext]="{ $implicit: data }">
      </ng-template>
    </tr>`
})
export class ListComponent {
  @Input() items;
  @ContentChild(TemplateRef) template: TemplateRef;
  constructor() { }
}

wrapper.component.ts

import { Component, ContentChild, TemplateRef } from '@angular/core';
@Component({
  selector: 'wrapper',
  template: `
    <table>
      <list [items]="items">
        <ng-template let-data>
          <td>{{data.category}}</td>
          <td>{{data.number}}</td>
        </ng-template>
      </list>
    </table>`
})
export class WrapperComponent {
  items = [
    { title: 'T1', category: 'C1', number: 'N1' },
    { title: 'T2', category: 'C2', number: 'N2' },
    { title: 'T3', category: 'C3', number: 'N3' }
  ];
  @ContentChild(TemplateRef) template: TemplateRef;
  constructor() { }
}

我还创建了一个 Plunker 演示...

@dhilt的答案是一个很好的实现,但我有一种方法可以使它对命名插槽和单个插槽有用:

// list.component.ts
import { Component, Input, TemplateRef } from '@angular/core';
@Component({
  selector: 'list',
  template: `
    <tr class="box" *ngFor="let data of items">
      <td>{{data.title}}</td>
      <ng-template
        [ngTemplateOutlet]="template"
        [ngTemplateOutletContext]="{ $implicit: data }">
      </ng-template>
    </tr>`
})
export class ListComponent<T extends {title: any}> {
  @Input() items: T[];
  @Input() template: TemplateRef<{$implicit: T}>;
  constructor() { }
}
// wrapper.component.ts
import { Component } from '@angular/core';
@Component({
  selector: 'wrapper',
  template: `
    <table>
      <list [items]="items" [template]="itemTemplate"></list>
      <ng-template #itemTemplate let-data>
        <td>{{data.category}}</td>
        <td>{{data.number}}</td>
      </ng-template>
    </table>`
})
export class WrapperComponent {
  items = [
    { title: 'T1', category: 'C1', number: 'N1' },
    { title: 'T2', category: 'C2', number: 'N2' },
    { title: 'T3', category: 'C3', number: 'N3' }
  ];
  constructor() { }
}

这是 *ngTemplateOutlet 的 API 文档。甚至像*ngIf这样的其他指令也以这种方式使用模板。

相关内容

  • 没有找到相关文章

最新更新