如何使用模板引用?

How to use templateRef?

我正在尝试找到一种在 Angular2 中动态构建模板的方法。我在想 templateRef 可能会提供一种方法来做到这一点。但我可能是错的。

I found an example of templateRef being used here.

我在看这个例子中的 templateRef。我注意到语法是 [ng-for-template] 我也试过 [ngForTemplate] 因为我知道这最近发生了变化。

所以现在我有这个:

import {Component, TemplateRef} from 'angular2/core';

@Component({
    selector : 'body',
    template : `
        <template [ngForTemplate]="container">
            <div class="container"></div>
        </template>
    `
})

export class App
{
    @ContentChild(TemplateRef) container;

    constructor() {}

    ngAfterContentInit()
    {
        console.log(this);
    }
}

这个例子抛出一个错误:

Can't bind to 'ngForTemplate' since it isn't a known native property

所以首先我想知道。这样做的正确方法是什么? The docs don't provide any examples.

其次,有没有什么好的方法可以将新的模板逻辑添加到我的模板或动态构建模板?应用程序的结构可以是非常大量的不同结构组合。因此,如果可能的话,我想看看是否有一种方法可以在没有包含大量不同 ngIf 和 ngSwitch 语句的巨大模板的情况下做到这一点。

我的问题实际上是关于 templateRef 的第一部分。但对第二部分的任何帮助或建议表示赞赏。

ngForTemplate 仅支持 ngFor

<template [ngFor] [ngForOf]="..." [ngForTemplate]="container"

<div *ngFor="..." [ngForTemplate]="container"

不在普通模板上。这是 NgFor directive

上的 @Input()

另一种使用方式TemplateRef

如果您有对 ViewContainerRef 的引用,您可以将其用于 "stamp" 模板

constructor(private _viewContainer: ViewContainerRef) { }

ngOnInit() {
  this.childView = this._viewContainer.createEmbeddedView(this.templ);
  this.childView.setLocal('data', this.data);
}

创建自己的模板指令并不难,您必须了解两个主要内容

  • TemplateRef 包含您的 <template> 标签中的内容
  • ViewContainerRef 正如 Gunter 所评论的那样,持有模板的视图,并允许您将模板中的内容嵌入到视图本身中。

我将使用我尝试解决此问题时的示例 issue,我的方法不是最好的方法,但它可以解释它是如何工作的。

我也想澄清一下,你可以为你的模板使用任何属性,即使它们已经被内置指令使用(显然这不是一个好主意,但你可以这样做)。

考虑一下我的 ngIfIn 方法(我糟糕的方法)

<template  [ngIfValue]="'make'" [ngIfIn]="obj">
  This will print
</template>
<template [ngIfValue]="'notExistingValue'" [ngIfIn]="obj">
  This won't print
</template>

我们这里有两个模板,每个模板使用两个输入 ngIfInngIfValue,所以我需要我的指令通过这两个输入获取模板并获取它们的值,所以它看起来像这个

@Directive({
  selector : '[ngIfIn][ngIfValue]',
  inputs : ['ngIfIn', 'ngIfValue']
})

首先我需要注入我上面提到的两个类

constructor(private _vr: ViewContainerRef, private _tr: TemplateRef) {}

我还需要缓存我通过输入传递的值

  _value: any;
  _obj: any;

  // Value passed through <template [ngIfValue]="'...'">
  set ngIfValue(value: any) {
    this._value = value;
  }

  // Value passed through <template [ngIfIn]="...">
  set ngIfIn(obj: any) {
    this._obj = obj;
  }

在我的例子中,我依赖于这两个值,我可以在 ngOnInit 中有我的逻辑,但是那会 运行 一次并且不会监听任何输入的变化,所以我将逻辑放在 ngOnChanges 中。请记住 ngOnChanges 在检查数据绑定属性之后立即调用,在检查视图和内容子项之前是否至少有一个已更改 (复制并粘贴自文档)。

现在我基本上是复制粘贴NgIf逻辑(不是很复杂,但相似)

  // ngOnChanges so this gets re-evaluated when one of the inputs change its value
  ngOnChanges(changes) {
    if(this._value in this._obj) {

      // If the condition is true, we embed our template content (TemplateRef) into the view
      this._vr.createEmbeddedView(this._tr);
    } else {

      // If the condition is false we remove the content of the view
      this._vr.clear();
    }
  }

如您所见,它并没有那么复杂:获取 TemplateRef,获取 ViewContainerRef,执行一些逻辑并使用 ViewContainerRef 将 TemplateRef 嵌入到视图中。

希望我说清楚了,我也说清楚了如何使用它们。这是一个 plnkr 我解释过的例子。