web-dev-qa-db-ja.com

templateRefの使用方法

私はAngular2でテンプレートを動的に構築する方法を見つけようとしています。 templateRefがこれを行う方法を提供するかもしれないと考えていました。しかし、私は間違っている可能性があります。

ここで使用されているtemplateRefの例を見つけました。

この例では、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);
    }
}

この例ではエラーがスローされます:

既知のネイティブプロパティではないため、「ngForTemplate」にバインドできません

だから最初に私は疑問に思っています。これを行う正しい方法は何ですか? ドキュメントは例を提供していません。

第二に、テンプレートに新しいテンプレートロジックを追加したり、テンプレートを動的に構築したりするための良い方法はありますか?アプリケーションの構造は、非常に大量の異なる構造の組み合わせになる場合があります。そのため、可能であれば、ngIfとngSwitchのさまざまなステートメントを含む巨大なテンプレートを使用せずにこれを実行できる方法があるかどうかを確認したいと思います。

私の質問は、実際にはtemplateRefに関する最初の部分です。ただし、2番目の部分に関するヘルプや提案は歓迎します。

17
Kris Hollenbeck

独自のテンプレートディレクティブを作成することは難しくありません。主に2つのことを理解する必要があります。

  • 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の2つの入力を使用する2つのテンプレートがあるので、これらの2つの入力でテンプレートを取得して値を取得するためのディレクティブが必要なので、次のようになります

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

まず、上記の2つのクラスを注入する必要があります

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;
  }

私の場合、これらの2つの値に依存し、ロジックをngOnInitに持つことができますが、それは1回実行され、入力の変更をリッスンしないため、ロジックをngOnChangesngOnChangesは、データバインドプロパティがチェックされた直後、少なくとも1つがビューとコンテンツの子がチェックされる前に呼び出されることに注意してください。変更されました(ドキュメントからコピーして貼り付けます)。

今、私は基本的にコピーして貼り付けます NgIf logic(それほど複雑ではありませんが、類似しています)

  // 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 は、私が説明した例です。

16
Eric Martinez

ngForTemplatengForでのみサポートされます

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

または

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

プレーンなテンプレートではありません。 NgForディレクティブの@Input()です

TemplateRefを使用する別の方法

ViewContainerRefへの参照がある場合は、それを使用してテンプレートに「スタンプ」することができます

_constructor(private _viewContainer: ViewContainerRef) { }

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