web-dev-qa-db-fra.com

Comment utiliser templateRef?

J'essaie de trouver un moyen de construire dynamiquement un modèle dans Angular2. Je pensais que templateRef pourrait fournir un moyen de le faire. Mais je peux me tromper.

J'ai trouvé un exemple de templateRef utilisé ici.

Je regardais templateRef dans cet exemple. J'ai remarqué que la syntaxe est [ng-for-template] J'ai aussi essayé [ngForTemplate] car je sais que cela a changé récemment.

Donc en ce moment, j'ai ceci:

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

Cet exemple génère une erreur:

Impossible de se lier à 'ngForTemplate' car ce n'est pas une propriété native connue

Je me demande donc d'abord. Quel est le bon moyen de le faire? Les documents ne fournissent aucun exemple.

Deuxièmement, existe-t-il un bon moyen d'ajouter une nouvelle logique de modèle à mon modèle ou de créer dynamiquement un modèle? La structure de l'application peut être une très grande quantité de combinaisons structurelles différentes. Donc, si possible, je voudrais voir s'il y a un moyen de le faire sans avoir un énorme modèle avec un tas d'instructions ngIf et ngSwitch différentes.

Ma question est vraiment la première partie sur templateRef. Mais toute aide ou suggestion sur la deuxième partie est appréciée.

17
Kris Hollenbeck

Créer votre propre directive modèle n'est pas difficile, vous devez comprendre deux choses principales

  • TemplateRef contient le contenu de votre <template> tag
  • ViewContainerRef comme commenté par Gunter, contient la vue du modèle et vous permettra d'incorporer ce qui est à l'intérieur du modèle dans la vue elle-même.

J'utiliserai un exemple que j'ai lorsque j'ai essayé de résoudre ce problème problème , mon approche n'est pas la meilleure pour cela, mais cela fonctionnera pour expliquer comment cela fonctionne.

Je tiens également à préciser que vous pouvez utiliser n'importe quel attribut pour vos modèles, même s'ils sont déjà utilisés par des directives intégrées (évidemment, ce n'est pas une bonne idée, mais vous pouvez le faire).

Considérez mon approche pour ngIfIn (ma mauvaise approche)

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

Nous avons ici deux modèles utilisant deux entrées chacun ngIfIn et ngIfValue, j'ai donc besoin de ma directive pour saisir le modèle par ces deux entrées et obtenir leurs valeurs aussi, donc cela ressemblerait à ceci

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

Je dois d'abord injecter les deux classes que j'ai mentionnées ci-dessus

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

J'ai également besoin de mettre en cache les valeurs que je passe par les entrées

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

Dans mon cas, je dépend de ces deux valeurs, je pourrais avoir ma logique dans ngOnInit mais cela fonctionnerait une fois et n'écouterait pas les changements dans aucune des entrées, alors j'ai mis la logique dans ngOnChanges. N'oubliez pas que ngOnChanges est appelé juste après que les propriétés liées aux données ont été vérifiées et avant que la vue et le contenu ne soient vérifiés si au moins l'un d'eux a changé (copier-coller à partir des documents).

Maintenant, je copie et colle fondamentalement NgIf logique (pas si complexe, mais similaire)

  // 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();
    }
  }

Comme vous le voyez, ce n'est pas si compliqué: prenez un TemplateRef, prenez un ViewContainerRef, faites de la logique et incorporez le TemplateRef dans la vue à l'aide de ViewContainerRef.

Si tout va bien je me suis fait clair et j'ai fait comment les utiliser assez clair aussi. Voici un plnkr avec l'exemple que j'ai expliqué.

16
Eric Martinez

ngForTemplate n'est pris en charge qu'avec ngFor

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

ou

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

pas sur un modèle simple. C'est une @Input() sur la directive NgFor

Une autre façon d'utiliser TemplateRef

Si vous avez une référence à ViewContainerRef vous pouvez l'utiliser pour "tamponner" le modèle

constructor(private _viewContainer: ViewContainerRef) { }

ngOnInit() {
  this.childView = this._viewContainer.createEmbeddedView(this.templ);
  this.childView.setLocal('data', this.data);
}
4
Günter Zöchbauer