In this post, I will show you how to programmatically set focus on a form control in Angular.
Instead of the popular ElementRef
solution, we will use Renderer2 to set focus on a form input. This approach is secure, easier to test and compatible with reactive forms.
Table of contents
Here’s a live demo on how to focus on form input in Angular Material:
Using ElementRef
First of all, I have seen many Angular examples that involve using ElementRef to get access to the native HTML element and calling focus()
. The following is from a recent example I have seen from codeburst.
In this approach, you reference the HTML input element with ViewChild
in typescript code.
ElementRef is included in Angular core library. It is a wrapper around native HTML elements.
The variable nameField
above refers to a native HTML element, which we can manipulate in code.
Security Risks
ElementRef in Angular gives direct access to HTML DOM (Document Object Model). Allowing direct access to the DOM can make your application vulnerable to XSS attacks.
You should always avoid using ElementRef in Angular where possible.
Separation of concerns
Relying on ElementRef for HTML DOM operations like form input focus and blur creates tight coupling between the application and rendering layers. So if you wanted use web workers, it will be impossible to separate the application logic from DOM manipulation code.
Focusing input with Renderer2
Renderer2 is a service that comes with the core Angular package. It allows DOM manipulation in a safe way.
It’s a bit like jQuery for Angular.
Although, I have a reactive form below for demonstration, all you need is an input with a unique id.
<form [formGroup]="form">
<mat-form-field class="full-width">
<input matInput id="myInput" formControlName="myInput" placeholder="Focused Input">
</mat-form-field>
<br>
<button mat-raised-button color="primary" (click)="focusMyInput()">Focus</button>
</form>
Code language: HTML, XML (xml)
Inject Renderer 2 in the constructor and access the input element with selectRootElement()
method.
Then, we can focus on the input using focus
method:
constructor(private renderer: Renderer2) {}
focusMyInput() {
this.renderer.selectRootElement('#myInput').focus();
}
Code language: TypeScript (typescript)
In addition, you can focus on input element on load, using the ngAfterViewInit()
hook.
ngAfterViewInit() {
setTimeout(() => {
var element = this.renderer.selectRootElement('#myInput');
element.focus();
}, 1000);
}
Code language: TypeScript (typescript)
Another useful feature of Renderer2 is that you can listen for events on elements.
For example, you can subscribe to the focus and blur events of the input with listen()
method.
In the code snippet below, we are grabbing the input element and subscribing to focus and blur events.
ngAfterViewInit() {
setTimeout(() => {
var elem = this.renderer.selectRootElement('#myInput');
this.renderer.listen(elem, "focus", () => { console.log('focus') });
this.renderer.listen(elem, "blur", () => { console.log('blur') });
}, 1000);
}
Code language: TypeScript (typescript)
It is important that you setup listeners in ngAfterViewInit()
hook as the element won’t be initialised in ngOnInit()
.
There you have it! That’s how to set focus on form control with Renderer2 in Angular.
Hi the console.log message didn’t appear on the console. I am not sure if blur actually run