TemplateRefs in Angular
Tags: angular, contentprojection, templaterefs
Published: 2019-05-29 22:49:04

---
title: TemplateRefs in Angular
published: true
tags: [angular, content projection, templaterefs]
canonical_url: https://www.prestonlamb.com/blog/angular-template-refs
---

If you're anything like me, you've heard of `TemplateRef`s in Angular, but didn't know what that meant. And it probably scared you off from learning what they are or how they work. But it's really not that scary of a thing to learn. It just takes a little bit of work and some practice, and the benefit can be huge.

I first learned about `TemplateRef`s from [this article](https://blog.angularindepth.com/templaterefs-are-angulars-render-props-a2b97cbcc362) by Isaac Mann. It caught my eye because I'd heard a lot about render props in React, but didn't really know how that applied to Angular. I ended up reading several of Isaac's articles on `ng-template`s and `TemplateRef`s. They are great articles, and you can [find them all here](https://blog.angularindepth.com/@isaacplmann).

Alright, let's get to it. I learned the following things while adding a `TemplateRef` component option to the `angular-tag-select` package that I manage. Up until now, to use the component meant that you had to use the styles that I had determined. There were a settings that you could pass in on an object that changed some of the styles. Those options included the icon classes, for example, and were very limited. And overwriting any of the default styles was difficult. So I wanted to provide a way for people to get the benefit of the tag select component without being tied down to the default styles.

There are two basic parts when creating a component that uses `TemplateRef`s. The first is in the template. The template should contain an element to output the template that the user will see. This could be a `div` or some other HTML element, or it can be an `<ng-container>`. If you use a an HTML element, that element will show up on the page. If you use `<ng-container>`, then there won't be any extra elements on the page. Here's an example template using `<ng-container>`:

```html
<ng-container *ngTemplateOutlet="layoutTemplate; context: ctx"></ng-container>
```

The `*ngTemplateOutlet` has two parts: the `layoutTemplate` and the `context`. The `layoutTemplate` is a class variable decorated with the `@ContentChild()` decorator from Angular. This is what allows you to pass an `<ng-template>` into this component from the parent component. The `context` is what allows you to make class variables accessible in the parent component. It's an object with variables and functions that you would like to have access to.

```ts
public ctx: any = {
    tagsSelectedAtStart: this.tagsSelectedAtStart,
    possibleTags: this.possibleTags,
    selectedTags: this.selectedTags,
    fns: {
        toggleTag: this.toggleTag,
    }
};
```

The other important part of implementing a component that uses a `TemplateRef` is in the parent component. Let's say that our `TemplateRef` component is the `<tag-select>` component, and we're implementing this component in our application in a `<submit-form>` component. This is the very basics of what the `<submit-form>` component template should look like:

```html
<tag-select>
    <ng-template>
        <!-- HTML to display parts of the tag-select component -->
    </ng-template>
</tag-select>
```

The `<tag-select>` component is put on the page, and then the `<ng-template>` tag inside there is why and where you can pass in the display elements of the `<tag-select>` component. In this case, with this component, you need two basic parts to display: the selected tags and the tags that are possible for selection. However you want to show those, the HTML for it needs to go between the `<ng-template>` tag.

Now, do you remember on the `<ng-container>` tag we declared the `context` variable? We access those variables in the parent in the following way:

```html
<tag-select>
    <ng-template let-selected="selected" let-possible="possible">
        <!-- HTML to display parts of the tag-select component -->
    </ng-template>
</tag-select>
```

After doing that, we can gain access to the internal class variables. In this case, it gives us access to the list of tags that have been selected and the list of possible tags as well so we can display those two lists however we want. You will very likely have functions exposed on the context as well.

There are a couple things to remember about the `context`, if you declare it using a class variable like is seen above, and the functions you expose. The first is that every time one of the internal class variables is updated, the context needs to be explicitly updated as well. If you declare the `context` in the following way, you won't need to explicitly update the context any time something changes; Angular will do it for you:

```html
<ng-container *ngTemplateOutlet="layoutTemplate; context: { selected: selected, possible: possible }">
</ng-container>
```

As for the functions, if you just use the normal syntax for writing a function in a component, you'll run into issues with `undefined` variables. To get around that, use arrow functions. The following pictures will demonstrate.

```ts
toggleTag = (tag: Tag) => {
    // Do Stuff
    this.updateContext('selected', this.selected)
}

updateContext(key: string, value: any) {
    this.ctx[key] = value;
}
```

I know this all seems very complicated, but once i jumped in and started trying it out it wasn't too bad. I still have a lot of practice and a long ways to go, but I'm excited about the possibilities that this will open for me as an Angular developer. The ability to use or provide packages that do the complex logic for the end user, but allow them to determine the look and feel is really powerful. It's why this pattern has become so popular in React.