The Angular template variable you are missing — Return of the VAR

Shlomi Assaf
4 min readApr 22, 2018

--

Angular template reference variables are with us from day 1 yet it feels like they are not getting the proper attention they deserve.

In this post I would like to demonstrate a nice technique that will help us solving performance challenges in our angular applications and in general do less work.

In a nut shell, with template reference variables we can access object’s on the template. DOM elements, directives or components. We can pass the reference to the component using a query or as a parameter in a template invoked method.

This post does not cover template variables in-depth, for an intro I recommend this ng-conf talk:

Let’s start with a problem. We have an array with 20 objects that we display using an *ngFor expression. For each item that we display we register to the click event.

Our task is to paint a border around the item when clicked and remove it when clicked again, repeating the process over and over — a toggle.

Let’s explore some of the possible solutions:

One solution the usually pop up is to set a new property on each object stating if to show (or not to show) the border. While this works, it is a mutating solution, we change the object. What if we are dealing with a table? maybe this object is later sent to a server, or maybe we are working with immutable objects? this is bad practice. There other variations of this approach, using symbols, non-enumerable getters etc…

Another solution might be a lookup object. An Array or a Map we can use to lookup which item is toggled. This has a management overhead, which requires that we keep track of items that are added and/or removed. The lookup might be expansive, working with large collections and it mixes UI state with, what is usually, a page component. With some optimisation, choosing the right tools and working smart we can pool this off, but it doesn’t feel right.

We can do better, and you probably guessed it right — using template variables.

The directive is very simple, it does nothing but exposing an object which we can assign any value to.

We call this directive var because it serves as a variable that we can use to store data on. It lives inside the template and does not go through the component (although we can do that).

To use it we simple set it as an attribute of an element and set#myVar=var on the same element so it is exported and ready to use. myVar is now an object we can use within the template.

For simplicity, our data object is an array of numbers.

We don’t need the component, we will work on the template:

Template using a scoped var for each item
DEMO: Template using a scoped var for each item

It’s important to note that we call it var but it does not follow the same rules that apply on a JavaScript var. Angular docs says template variables are global to the entire template, but this is per template, *ngIf *ngFor ng-container and other constructs create a new scope block.

In the example above we created an instance of thevar directive for each item in our collection. It is working because each iteration of *ngFor creates a new template variable scope block and so each template get’s a fresh instance of var.

Sometimes we need to work within a single scope, meaning one instance of var. We can try a different implementation but let’s upgrade the directive first:

Now we can accept an input, an object that we will use to assign pre-defined values to the directive, an sort of initializer.

Now we can try a new approach, instead of a new instance for var for every item we will create a single, top-level var with an array that we map to our collection.

Template using a single top-level var for all items
DEMO: Template using a single top-level var for all items

We initialize the var with an array and use the array as our toggle list.

This is pretty much it. You can use it for other scenarios, for example toggling of animations without a component state, only template state.

If you have other use cases please comment. If you have upgrades in mind please share and of course if you have any notes/fixes/issues please comment bellow.

Thank you for reading.

--

--