【问题标题】:How to render nested ng-template如何渲染嵌套的 ng-template
【发布时间】:2017-11-20 21:25:39
【问题描述】:

我有这样的嵌套ng-template 结构。

@Component({
  selector: 'my-app',
  template: `
    <list>
      <ng-template *ngFor="let item of Items" #ListItem>
        <ng-template #ListItemLine>{{ item[0] }}</ng-template>
        <ng-template #ListItemLine>{{ item[1] }}</ng-template>
        <ng-template #ListItemLine>{{ item[2] }}</ng-template>
        I can see this line, but can't get above templates
      </ng-template>
    </list>
  `,
})
export class App {
  Items: Array<Array<string>> = [
    [ "1-1", "1-2", "1-3", ],
    [ "2-1", "2-2", "2-3", ],
    [ "3-1", "3-2", "3-3", ],
    [ "4-1", "4-2", "4-3", ],
    [ "5-1", "5-2", "5-3", ],
  ]
}

如何在我的组件中渲染子 ng-component

@Component({
  selector: 'list',
  template: `
    <ul>
      <li *ngFor="let item of Items">
        <ng-container *ngTemplateOutlet="item"></ng-container>
      </li>
    </ul>
  `,
})
export class ListComponent {

  @ContentChildren('ListItem') public Items;

}

Plunkr https://plnkr.co/edit/Hi1ZqPAAYyIbclUuzRrl?p=preview

提前谢谢你。

更新

最后我想将 Angular Material 组件包装到我的组件中,所以如果我能找到比 Material 更好的 UI,我不应该在我的程序中更改 Material 组件的所有精度,我只需要更改我的包装 UI 组件的实现。

例如,让我们尝试包装mat-list 组件。我需要为mat-list 容器做一个包装器,我们称之为my-list

@Component({
  selector: 'my-list',
  template: `
    <mat-list>
      <ng-content></ng-content>
    </mat-list>
  `,
})

mat-list-item 的包装器:

@Component({
  selector: 'my-list-item',
  template: `
    <mat-list-item>
      <ng-content></ng-content>
    </mat-list>
  `,
})

HTML 渲染结果将是:

  • 我的列表
    • 垫子列表
      • 我的列表项
        • 垫列表项
      • ...

每个 Material 组件都被我的包装器包围,因此 Material 附带的指令和样式将不起作用。

【问题讨论】:

  • 我不认为你真的需要嵌套模板。你能解释更多你想要达到的目标吗?
  • 只有父模板会在您的代码中呈现,因为您只选择父模板。 @ContentChildren('ListItem') 仅选择顶级模板,因此仅呈现那些模板。要渲染子模板,您必须对它们做一些事情。也许您应该只使用普通的 *ngfor 来扩展父模板内的嵌套对象并避免嵌套模板。
  • @AlesD ng-template 让我有机会在没有包装器元素的情况下呈现它的内容,因此ng-template 的嵌套结构应该让我有机会在没有包装器的情况下呈现元素树。最后,我想将 Material 列表组件封装在我的组件中,并且能够使用像 matLine 这样的指令,如果包裹起来就不起作用。
  • @AlesD 是的,我知道我不渲染它们,因为我不知道如何引用它们。
  • 如果您想从另一个模板中引用它们,您需要在代码中执行此操作,我仍然认为您想要做的事情有更好的解决方案。如果要构建递归树结构,可以构建递归组件。

标签: angular ng-template


【解决方案1】:

根据您提供的信息,我将如何解决此问题。正如您已经建议的那样,我制作了两个组件listlist-item。 列表组件基于输入数组呈现list-item 组件,并且列表组件的内容必须包含定义列表项模板的模板。示例代码:

    @Component({
      selector: 'list',
      template: `
        <ul>
          <list-item *ngFor="let item of items" [data]="item" [itemTemplate]="itemTemplate"></list-item>
          <ng-content></ng-content>
        </ul>
      `,
    })
    export class ListComponent {
      @ContentChild(TemplateRef)
      public itemTemplate: TemplateRef;
      @Input()
      public items: any[];

    }

然后list-item 组件只渲染a 容器元素中提供的列表项模板。示例代码:

@Component({
  selector: 'list-item',
  template: `
      <li>
        <ng-container *ngTemplateOutlet="itemTemplate; itemContext"></ng-container>
      </li>
  `,
})
export class ListItemComponent {
  @Input()
  public data: any;
  @Input()
  public itemTemplate: Template;
  public get itemContext(): any {
    return { $implicit: data };
  }
}

然后您可以以不同的方式使用它。我举了一个例子,只是一个简单的列表,另一个例子是项目模板又是一个列表,所以你得到一个类似于树的列表列表。示例代码:

@Component({
  selector: 'my-app',
  template: `
    <list [items]="Items">
      <ng-template let-items>{{ items | json }}</ng-template>
    </list>
    <list [items]="Items">
      <ng-template let-items>
        <list [items]="items">
          <ng-template let-items>{{ items | json }}</ng-template>
        </list>
      </ng-template>
    </list>
  `,
})
export class App {
  Items: Array<Array<string>> = [
    [ "1-1", "1-2", "1-3", ],
    [ "2-1", "2-2", "2-3", ],
    [ "3-1", "3-2", "3-3", ],
    [ "4-1", "4-2", "4-3", ],
    [ "5-1", "5-2", "5-3", ],
  ]
}

我还制作了一个带有代码的 plunker 示例,您可以在其中运行它。 Plunker Sample

【讨论】:

  • 感谢您的帮助,但这不是我所期望的。看起来ng-templateng-container 的可能性不足以满足我的目的。您的示例通过输入传递数据,我希望所有数据都通过内容传递。无论如何,您的示例非常有帮助。我会做一些解决方法,也许稍后会做一些自定义模板。
猜你喜欢
  • 2019-01-31
  • 2021-07-25
  • 1970-01-01
  • 2019-04-11
  • 2020-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多