How to use templateRef?

Creating your own template directive it's not difficult, you have to understand two main things

  • TemplateRef contains what's inside your <template> tag
  • ViewContainerRef as commented by Gunter, holds the template's view and will let you to embed what's inside the template into the view itself.

I will use an example I have when I tried to solve this issue, my approach is not the best for that, but it will work for explaining how it works.

I want to clarify too that you can use any attribute for your templates, even if they're already used by builtin directives (obviously this is not a good idea, but you can do it).

Consider my approach for ngIfIn (my poor approach)

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

We have here two templates using two inputs each ngIfIn and ngIfValue, so I need my directive to grab the template by these two inputs and get their values too, so it would look like this

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

First I need to inject the two classes I mentioned above

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

I also need to cache the values I'm passing through the inputs

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

In my case I depend on these two values, I could have my logic in ngOnInit but that would run once and wouldn't listen for changes in any of the inputs, so I put the logic in ngOnChanges. Remember that ngOnChanges is called right after the data-bound properties have been checked and before view and content children are checked if at least one of them has changed (copy and paste from the docs).

Now I basically copy & paste NgIf logic (not so complex, but similar)

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

As you see it's not that complicated : Grab a TemplateRef, grab a ViewContainerRef, do some logic and embed the TemplateRef in the view using ViewContainerRef.

Hopefully I made myself clear and I made how to use them clear enough also. Here's a plnkr with the example I explained.


ngForTemplate is only supported with ngFor

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

or

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

not on a plain template. It is an @Input() on the NgFor directive

Another way to use TemplateRef

If you have a reference to ViewContainerRef you can use it to "stamp" the template

constructor(private _viewContainer: ViewContainerRef) { }

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