In this post you’ll learn how to use Template Reference Variables, often known as “Template Refs”, in Angular.
In Angular, components have a template
property, that holds elements and other components. A template reference variable is a feature that allows us to gain access to a part of our template.
This could be an element, component, or could be a directive. Template reference variables are cleverly implemented and can be used in various ways.
The first might be to simply export a reference to an element. Here we can attach a #
to an <input>
and provide a variable name (hence the template reference ‘variable’):
<input type="text" #coffee>
You can think of this syntax as an “export”. We are exporting a reference to the element.
That means that we can now access properties on that reference variable as if it was returned to us through plain JavaScript (think what you’d get back using document.querySelector('input')
and that’s what we have here):
<input type="text" #coffee>
<p>{{ coffee.value }}</p>
This would log out an empty string for coffee.value
as we have no value
. Our coffee
variable is directly giving us an HTMLInputElement
.
Free eBook
Directives, simple right? Wrong! On the outside they look simple, but even skilled Angular devs haven’t grasped every concept in this eBook.
- Observables and Async Pipe
- Identity Checking and Performance
- Web Components <ng-template> syntax
- <ng-container> and Observable Composition
- Advanced Rendering Patterns
- Setters and Getters for Styles and Class Bindings
For us to see the value as we type, we would need to introduce the ngModel
Directive:
<input type="text" ngModel #coffee>
<p>{{ coffee.value }}</p>
Give it a try and type something into the <input>
:
So here’s the next great feature of template refs.
Let’s export a reference to our ngModel
and change the context of what #coffee
returns us.
By specifying #coffee
we are implicitly letting Angular decide what to export, because we are not specifying anything other than binding to the element.
We’re binding ngModel
, which is now ‘part of’ our <input>
. Let’s export it:
<input type="text" ngModel #coffee="ngModel">
<p>Value: {{ coffee.value }}</p>
<p>Pristine: {{ coffee.pristine }}</p>
<p>Touched: {{ coffee.touched }}</p>
By passing #coffee="ngModel"
we are explicitly binding a reference to our tracked ngModel
directive.
No longer do we have an HTMLInputElement
. We have a reference to NgControl
.
You can check the source code for NgControl here, which extends the NgControl and AbstractControlDirective classes.
Why are we looking at this? Because it shows you every property available to you, which is exactly why we’ve referenced not only value
but pristine
and touched
as well.
Try them out below, our template reference variable is mirroring the ngModel
:
We can further this and access a template ref inside a component, so we can access properties and methods from inside the class
and not just the template
.
This is achieved through using perhaps TemplateRef
or ElementRef
alongside a @ViewChild
decorator. Read the above article on how to do it and more deep working, but essentially it looks like this:
@Component({...})
export class AppComponent {
@ViewChild('username') input: ElementRef<HTMLInputElement>;
}
That’s a nice introduction to template refs, and I hope it gives you some deeper understanding as to how to use them, when and where. Not only this, but what to expect back when you declare a template ref and how to also export references to things like directives.
If you are serious about your Angular skills, your next step is to take a look at my Angular courses where you’ll learn Angular, TypeScript, RxJS and state management principles from beginning to expert level.
Happy reffing!