Angular 4+:
Use renderer.selectRootElement
with a CSS selector to access the element.
I've got a form that initially displays an email input. After the email is entered, the form will be expanded to allow them to continue adding information relating to their project. However, if they are not an existing client, the form will include an address section above the project information section.
As of now, the data entry portion has not been broken up into components, so the sections are managed with *ngIf directives. I need to set focus on the project notes field if they are an existing client, or the first name field if they are new.
I tried the solutions with no success. However, Update 3 in this answer gave me half of the eventual solution. The other half came from MatteoNY's response in this thread. The result is this:
import { NgZone, Renderer } from '@angular/core';
constructor(private ngZone: NgZone, private renderer: Renderer) {}
setFocus(selector: string): void {
this.ngZone.runOutsideAngular(() => {
setTimeout(() => {
this.renderer.selectRootElement(selector).focus();
}, 0);
});
}
submitEmail(email: string): void {
// Verify existence of customer
...
if (this.newCustomer) {
this.setFocus('#firstname');
} else {
this.setFocus('#description');
}
}
Since the only thing I'm doing is setting the focus on an element, I don't need to concern myself with change detection, so I can actually run the call to renderer.selectRootElement
outside of Angular. Because I need to give the new sections time to render, the element section is wrapped in a timeout to allow the rendering threads time to catch up before the element selection is attempted. Once all that is setup, I can simply call the element using basic CSS selectors.
I know this example dealt primarily with the focus event, but it's hard for me that this couldn't be used in other contexts.
UPDATE: Angular dropped support for Renderer
in Angular 4 and removed it completely in Angular 9. This solution should not be impacted by the migration to Renderer2
. Please refer to this link for additional information:
Renderer migration to Renderer2