使用ngTemplateOutlet的Angular 2+

时间:2018-07-25 14:44:42

标签: angular typescript

我正在尝试遵循本教程:

https://alligator.io/angular/reusable-components-ngtemplateoutlet/

但是如果我复制代码,它将无法正常工作。它显示:

<ul>
<li></li>
</ul>

代替

<ul>
<li>Static List Template</li>
</ul>

这些属性仍未定义:

@ContentChild(CardItemDirective, {read: TemplateRef}) cardItemTemplate;
@ContentChild(ListItemDirective, {read: TemplateRef}) listItemTemplate;

编辑:以前的plnkr不正确。忘了保存。看到这个:

https://next.plnkr.co/edit/b9kdTXoe8ZRqnuSv?open=lib%2Fapp.ts&deferRun=1&preview

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

@Directive({
  selector: '[cardItem]'
})
export class CardItemDirective {}

@Directive({
  selector: '[listItem]'
})
export class ListItemDirective {}


@Component({
  selector: 'card-or-list-view',
  template: `
  <ng-container [ngSwitch]="mode">
  <ng-container *ngSwitchCase="'card'">
    <ng-container *ngFor="let item of items">
      <ng-container *ngTemplateOutlet="cardItemTemplate"></ng-container>
    </ng-container>
  </ng-container>
  <ul *ngSwitchCase="'list'">
    <li *ngFor="let item of items">
      <ng-container *ngTemplateOutlet="listItemTemplate"></ng-container>
    </li>
  </ul>
  </ng-container>
  `
})
export class CardOrListViewComponent {

  @Input() items: any[] = [];

  @Input() mode: 'card' | 'list' = 'card';

  // Read in our structural directives as TemplateRefs
  @ContentChild(CardItemDirective, {read: TemplateRef}) cardItemTemplate;
  @ContentChild(ListItemDirective, {read: TemplateRef}) listItemTemplate;

}


@Component({
  selector: 'app-usage',
  template: `
    <card-or-list-view
        [items]="items"
        [mode]="mode">
      <div cardItem>
        Static Card Template
      </div>
      <li listItem>
        Static List Template
      </li>
    </card-or-list-view>
`
})
export class UsageExample {
  mode = 'list';
  items = [
    {
      header: 'Creating Reuseable Components with NgTemplateOutlet in Angular',
      content: 'The single responsibility principle...'
    } // ... more items
  ];
}

2 个答案:

答案 0 :(得分:3)

您必须将模板放入<ng-template>或使用asterisk-prefix syntax,以便可以与structural directive一起使用:

<ng-template listItem>
  <li>
    Static List Template
  </li>
</ng-template>

或更短:

<li *listItem>
  Static List Template
</li>

注意:您将带有两个嵌套的li标记。也许不是您想要的...

答案 1 :(得分:1)

您是正确的,因为永远不会定义ContentChildren,所以它们始终是未定义的。 ngTemplateOutlet将templateRef或组件作为参数,由于您的内容子级从不渲染,因此从未在代码中的任何位置定义它。我个人更喜欢使用ViewContainerRef / ComponentFactoryResolver路线:https://angular.io/guide/dynamic-component-loader

这使您可以更精细地控制组件,并可以通过编程方式设置@Input变量。希望这会有所帮助