Using Template Reference variables in Angular 7

This article is all about Template Reference variable or Local Reference variable, whatever you can say. I think you can get some idea with the name itself “Template Reference” which says we are looking forward to putting a reference to any template. Let me explain this with an example.
Let’s say we have some basic DOM elements in our template view. It can be anything like
<div>
<h2>I am h2</h2>
<p>I am Paragraph</p>
</div>
And we want to access the content of h2 tag element inside our template but not in the component class. After accessing it, we also want to display below the parent div. How can we do that?
The answer is “Template Reference variable”. Yes, by placing a template or local reference variable over that element.
Angular provides us, a way of capturing a reference to any specific dom element, component or directive in order to use it somewhere in our template itself.
We just have to mark that specific element with a name followed by hash(#) symbol. Once the element gets marked, it will be treated as a local reference variable for that template and can be used to access its properties inside the template view only. You can not access it inside the component class or typescript logic codes.
<div>
<h2 #h2Elm>I am h2</h2>
<p>I am Paragraph</p>
</div>
<hr>
{{h2Elm.textContent}}
insert
we can do the same here for component and directives too
<hello name="Template Ref Variable" #helloRef></hello>
{{helloRef.name}} //   Template Ref Variable
Note: The identifier name used for the template reference variable should be unique and should not conflict with any other template reference variable.
Well! I told you that you cannot access that template reference variable inside the component class or typescript logic but still, you can use that variable by passing it through a method which will be called by the event listener.
<div>
<label for="Name">Name</label>
<input type="text" #nameInput>
<button (click)="onSaveName(nameInput)">Save Name</button>
</div>
Passing that local variable with omitting # symbol.
import {
  Component,
} from '@angular/core';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  constructor() {}
  onSaveName(name: HTMLInputElement) {
    console.log(( < HTMLInputElement > name).value);
  }
}
Here, if you observe, we are expecting a name parameter which will be of type HTMLInputElement and also inside the body of the method, we have wrapped the name variable with the same type. It is because we are accessing the instance of the element which is <input> type.
insert
You can see in the above screenshot that all the generic properties of Input element are wrapped under HTMLInputElement. It is one of good practice to explicitly define the parameter type you are about to receive in the method to avoid further confusion with variable types in the method body. If you do so, Editor intellisense will show you all the methods and properties can be called on the received parameter property.
insert
Okay, now back to the topic….
But, There is one more way to accessing the template reference variable is using @ViewChild() decorator, using this decorator, we can reference that variable inside our component without passing it via method as a parameter, or we can say, if we need to access it before the onSaveName() method get executed.
import {
  Component,
  OnInit,
  ViewChild,
  ElementRef,
  AfterViewChecked
} from '@angular/core';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, AfterViewChecked {
  @ViewChild('nameInput') inputNameRef: ElementRef;
  constructor() {}
  ngOnInit() {}
  onSaveName(name: HTMLInputElement) {
    console.log(( < HTMLInputElement > name).value);
    console.log(this.inputNameRef.nativeElement.value);
  }
  ngAfterViewChecked() {
    console.log("After view got Checked");
    console.log(this.inputNameRef.nativeElement.value);
  }
}
Here, the output will be logged 3 times on the control, two for the method and one after AfterViewChecked lifecycle hook. Don’t forget that with the @ViewChild() decorator, our reference to the variable will be ElementRef type Since we are trying to access a reference to an element of our template view. ElementRef has sub-property called nativeElement which wraps all the underlying properties of that specific referenced element.
We can also get the value of input within the same template by placing a reference variable over it.
<input type="text" (change)="true" #groupRef >
{{groupRef.value}}
Here, whenever the change event occurs, the changes get detected by Angular Change detection system and we will get the value of input via string interpolation. Check the below output of the above code.
insert
or we can just bind the value accessed via local reference with ngModel. This will produce the same output as in the above example.
<input type="text" [ngModel]="groupRef.value" #groupRef >
{{groupRef.value}}
The value property of the input element is bound to ngModel. Although, you can also bind your custom string to [ngModel] like
[ngModel]="'abc'" //you will see "abc" in the input box
but, we just tried to assign the value property of input element which will hold whatever you type and then it will be passed to [ngModel] to render in the input box.
By here, we are at the end of this article but I have not discussed one important thing yet.
Note that if you use an <ng-template> or a structural directive like *ngIf or *ngFor it creates a new template scope and template reference variables
Wait, I can prove the above lines with the below example.
Let’s say we have an object “groupList” defined in the app.component.ts
groupList = [{
    name: ''
  },
  {
    name: ''
  }
]
And we have done some iteration over this object on the div element.
<div *ngFor="let group of groupList">
<input type="text" (blur)="group.name = groupRef.value"  #groupRef >
{{groupRef.value}}
</div>
<hr>
<pre>
{{groupList | json}}
</pre>
It will look like something below
insert

Thanks for reading this article. Please let me know your sugestions in the comment box.

People Reaction : 10

Aaron
24th May 19 AT 9:40 PM Aaron
Nice, clear article. Thanks
Maravarman
3rd Jul 19 AT 6:22 PM Maravarman
Thanks a lot for this nice article
Rohit Sharma
3rd Jul 19 AT 6:22 PM Rohit Sharma
Thank you, Maravarman
Yuliana Madeleine
24th Sep 19 AT 1:37 AM Yuliana Madeleine
Thank you, can you please add an example to apply this with a checkbox like:
<input type="checkbox" (change)="true" #checkboxSelected >
{{checkboxSelected.selected}} // Not sure if 'selected' can get "true" if checked and "false" if unchecked
Jeff Lebowski
26th Sep 19 AT 6:07 PM Jeff Lebowski
Information-dense and useful... Great article!
Mahendra K
2nd Oct 19 AT 2:12 PM Mahendra K
Good Explanation & Presentation of the web page Styling which is pleasant
Rohit Sharma
2nd Oct 19 AT 2:12 PM Rohit Sharma
Thank you so much, brother.
Mahendra K
2nd Oct 19 AT 2:15 PM Mahendra K
Nice Article, Pls add @ViewChildren, @ContentChild and @ContentChildren
Rohit Sharma
2nd Oct 19 AT 2:15 PM Rohit Sharma
Thank you, Mahendra. Sure I will add that too.
Andres Guevara
16th Oct 19 AT 9:10 PM Andres Guevara
Thank you so much, very useful
Amit Singh
26th Dec 19 AT 5:47 PM Amit Singh
very easy to understand
Rohit Sharma
Name : Email : Website :
© 2020 WriteSomeCode. All Right Reserved. A Rohit Sharma Blog. Creative Commons License licensed under a Creative Commons Attribution 4.0 International License