Не удается заставить ngTemplateOutlet работать

Я пытаюсь создать компонент списка в Angular2, который берет элементы, столбцы и шаблоны для полей элементов от пользователя компонента. Поэтому я пытаюсь использовать ngTemplateOutlet и ngOutletContext (которые я прочитал, являются экспериментальными). Но я не могу заставить его работать.

Вот упрощенный компонент, демонстрирующий, что я пытаюсь сделать:

<div *ngFor="let item of items>
  <span *ngFor="let column of columns>
    <template [ngOutletContext]="{ item: item }" 
              [ngTemplateOutlet]="column.templateRef"></template>
  </span>
</div>

Вот использование компонента:

<my-component [items]="cars" [columns]="carColumns">
  <template #model>{{item.model}}</template>
  <template #color>{{item.color}}</template>
  <template #gearbox>{{item.gearbox}}</template>
</my-component>

И вот примеры данных:

cars = [
  { model: "volvo", color: "blue", gearbox: "manual" },
  { model: "volvo", color: "yellow", gearbox: "manual" },
  { model: "ford", color: "blue", gearbox: "automatic" },
  { model: "mercedes", color: "silver", gearbox: "automatic" }
];

carColumns = [
  { templateRef: "model" },
  { templateRef: "color" },
  { templateRef: "gearbox" }
];

Вот плункер, воспроизводящий проблему после адаптации кода в соответствии с комментарием Günters: https://plnkr.co/edit/jB6ueHyEKOjpFZjxpWEv?p=preview

Ответы

Ответ 1

Вот как вам нужно это сделать:

@Component({
  selector: 'my-component',
  template: `
    <div *ngFor="let item of items">
      <span *ngFor="let column of columns">
        <template [ngTemplateOutlet]="column.ref" [ngOutletContext]="{ item: item }"></template>
      </span>
    </div>`
})
export class MyComponent {
  @Input() items: any[];
  @Input() columns: any[];
}

@Component({
  selector: 'my-app',
  template: `
    <div>
      <my-component [items]="cars" [columns]="columns">
        <template #model let-item="item">{{item?.model}}</template>
        <template #color let-item="item">{{item?.color}}</template>
      </my-component>
    </div>`
})
export class App {
  @ViewChild('model') model;
  @ViewChild('color') color;
  cars = [
      { model: "volvo", color: "blue" },
      { model: "saab", color: "yellow" },
      { model: "ford", color: "green" },
      { model: "vw", color: "orange" }
    ];

  ngAfterContentInit() {
    this.columns = [
      { ref: this.model },
      { ref: this.color ]
    ];
  }
}

Plunker

Ответ 2

обновление Angular 5

ngOutletContext было переименовано в ngTemplateOutletContext

См. также https://github.com/angular/angular/blob/master/CHANGELOG.md#500-beta5-2017-08-29

оригинальный

Не используйте [] и {{}} вместе. Либо тот, либо другой, но не оба.

Не используйте {{}}, если вы хотите передать объект, потому что {{}} используется для строковой интерполяции.

Это должно быть

[ngTemplateOutlet]="column.templateRef"

Пример плунжера

Ответ 3

Вы можете сделать это без ngOutletContext. Вы должны использовать NG-шаблон вместо шаблона. у меня работает следующий код:

app.component.html:

<div>
  <ng-template #c1>
    <app-child1></app-child1>
  </ng-template>
  <app-parent [templateChild1]="c1"></app-parent>
</div>

app-parent - это дочерний элемент приложения-компонента. app-child объявлен в app-component как шаблон, и этот шаблон используется в app-parent.

app.parent.html:

<p>
  <ng-template [ngTemplateOutlet]="templateChild1"></ng-template>
</p>

app.parent.ts:

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {

  @Input() public templateChild1: TemplateRef<any>;

  public ngOnInit() {
  }

}