Blog

I'm looking for:

Angular 2 TemplateRef Usage

Angular 2 is the hot new thing, but like any other new technology out there, documentation and examples are really sparse and there’s a lot of head scratching trying to figure out why things that seem like they should work…aren’t.

I spent some time recently working with TemplateRefs in Angular 2, trying to access templates defined via a <template> tag in my HTML from the component code.

Here’s what my component and html originally looked like:

&amp;amp;amp;amp;amp;lt;div id=&amp;amp;amp;amp;amp;quot;my-container&amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;gt;
  &amp;amp;amp;amp;amp;lt;template #tmplMyTemplate&amp;amp;amp;amp;amp;gt;
    &amp;amp;amp;amp;amp;lt;div (click)=&amp;amp;amp;amp;amp;quot;templateClick()&amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;gt;I'm a custom template!&amp;amp;amp;amp;amp;lt;/div&amp;amp;amp;amp;amp;gt;
  &amp;amp;amp;amp;amp;lt;/template&amp;amp;amp;amp;amp;gt;
&amp;amp;amp;amp;amp;lt;/div&amp;amp;amp;amp;amp;gt;
import { Component, ViewChild, TemplateRef, ViewContainerRef } from '@angular/core';

@Component({
  selector: 'my-selector',
  templateUrl: './my-component.component.html',
})
export class MyComponent {
  @ViewChild(&amp;amp;amp;amp;amp;quot;tmplMyTemplate&amp;amp;amp;amp;amp;quot;) tmplMyTemplate: TemplateRef&amp;amp;amp;amp;amp;lt;any&amp;amp;amp;amp;amp;gt;;

  constructor(private vcRef: ViewContainerRef) {
    this.vcRef.createEmbeddedView(this.tmplMyTemplate);
  }

  templateClick() {
    alert(&amp;amp;amp;amp;amp;quot;Success!&amp;amp;amp;amp;amp;quot;);
  }
}

I’m trying to get and use a TemplateRef to my <template> when the component is instantiated.  However when this is ran, the TemplateRef is always undefined and thus an error is thrown when I attempt to use it.  I know using the @ViewChild() decorator allows the component to fetch a template from the DOM (it can fetch other component/directives used inside the parent component as well) and assign it to a variable for use later in the code.  But it wasn’t working!

As is usually the case when things look syntactically correct but are still failing, the problem ended up being one of timing.  I dug through the Angular documentation for the component lifecycle and was able to piece together that at the time I’m trying to use the TemplateRef in my code (instantiation), the TemplateRefs haven’t yet been loaded.  Obvious once I realized it, but such is the way of programming.

Reading the lifecycle documentation, you’d think that ngAfterViewInit is when all the child views of the component are loaded and thus accessible, and while that is true I found in my testing that my templates were loaded by the time ngOnInit fires.  In most cases either method is probably going to be sufficient for whatever your code is trying to do with the TemplateRef (YMMV of course).

Here’s what my component looked like after adjustment:

import { Component, OnInit, ViewChild, TemplateRef, ViewContainerRef } from '@angular/core';

@Component({
  selector: 'my-selector',
  templateUrl: './my-component.component.html',
})
export class MyComponent implements OnInit {
  @ViewChild(&amp;amp;amp;amp;amp;quot;tmplMyTemplate&amp;amp;amp;amp;amp;quot;) tmplMyTemplate: TemplateRef&amp;amp;amp;amp;amp;lt;any&amp;amp;amp;amp;amp;gt;;

  constructor(private vcRef: ViewContainerRef) {
    // tmplMyTemplate is not yet loaded here
    //this.vcRef.createEmbeddedView(this.tmplMyTemplate);
  }

  ngOnInit() {
    this.vcRef.createEmbeddedView(this.tmplMyTemplate);
  }

  templateClick() {
    alert(&amp;amp;amp;amp;amp;quot;Success!&amp;amp;amp;amp;amp;quot;);
  }
}

And it works like a charm!


Looking for a new job? We work with some of the biggest names in tech, and we’re hiring! Check out our open jobs and make your next career move with Planet.