Подтвердить что ты не робот

Как использовать 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. Но любая помощь или предложения по второй части приветствуются.

4b9b3361

Ответ 1

Создать собственную шаблонную директиву не сложно, нужно понимать две основные вещи

  • TemplateRef содержит то, что внутри вашего <template>
  • ViewContainerRef как прокомментировал Гюнтер, содержит представление шаблона и позволит вам встроить то, что внутри шаблона, в само представление.

Я буду использовать пример, который у меня был, когда я пытался решить эту проблему, мой подход не самый лучший для этого, но он поможет объяснить, как он работает.

Я также хочу уточнить, что вы можете использовать любой атрибут для своих шаблонов, даже если они уже используются встроенными директивами (очевидно, это не очень хорошая идея, но вы можете это сделать).

Рассмотрим мой подход к ngIfIn (мой плохой подход)

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

Здесь у нас есть два шаблона, использующих два входа каждый ngIfIn и ngIfValue, поэтому мне нужна моя директива, чтобы получить шаблон этими двумя входами и получить их значения тоже, чтобы это выглядело так

@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, проделайте некоторую логику и внедрите TemplateRef в представление, используя ViewContainerRef.

Надеюсь, я прояснил себя и понял, как правильно их использовать. Вот plnkr с примером, который я объяснил.

Ответ 2

ngForTemplate поддерживается только с помощью ngFor

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

или

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

не на простой шаблон. Это @Input() в директиве ngFor

Другой способ использования TemplateRef

Если у вас есть ссылка на ViewContainerRef, вы можете использовать его для "штампа" шаблона

constructor(private _viewContainer: ViewContainerRef) { }

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