Reputation: 2408
I updated from Angular 2 to Angular 4 and in the docs it's written to use the Renderer2
instead of Renderer
which is deprecated.
Now am looking into the Renderer source, but cannot find a way to invoke the focus()
method as I used to.
Old method:
this.renderer.invokeElementMethod(element, 'focus', []);
What is the new aproach?
EDIT
What if the element i am focusing onto is obtained via QuerySelector
?
For instance:
let inputField = document.querySelectorAll('.dialog input');
if ( inputField[0] ) {
inputField[0].focus();
}
Since its obtained via QuerySelector
, the focus()
method doesn't exist on it.
Upvotes: 13
Views: 34695
Reputation: 303
If you are using Angular CDK, you can set focus using FocusMonitor.focusVia
method that is part of @angular/cdk/a11y
Accessibility module (A11yModule).
This way you can avoid any DOM manipulation and avoid referencing nativeElement
altogether.
import { FocusMonitor } from '@angular/cdk/a11y';
export class ExampleComponent implements AfterViewInit {
@ViewChild('elem', {static: false}) elemRef;
constructor(private focusMonitor: FocusMonitor) {
}
ngAfterViewInit() {
// Programmatically set focus. Focus source is 'program'.
this.focusMonitor.focusVia(this.elemRef, 'program');
}
}
Upvotes: 4
Reputation: 493
If you declare the correct type of your inputField
var, you can use any JS query selector.
For instances declaring:
let inputField: HTMLInputElement = document.querySelector('.dialog input');
enables you to call
inputField.focus();
that it will work and no TS error will be thrown.
Upvotes: 2
Reputation: 127
At this time, it appears that this task is not achievable without directly modifying the DOM. As others have said, the invokeElementMethod() is deprecated. However, you will find issues with using selectRootElement as well, as this is not its intended purpose and you will end up losing the children inside of your DIV. Here is a link to a SO question that explains selectRootElement in more detail (since the angular docs are atrocious):
Renderer multiple selectRootElement Issue (with plnkr provided)
As for now, it appears the only way to easily achieve your goal is to use a template reference variable, a view child, and the yourViewChild.nativeElement.focus() (though this practice is also not recommended)
There is also a suggested workaround using a FocusService found on this GitHub issue: https://github.com/angular/angular/issues/15674
In this issue, Tytskyi mentions that you can implement a FocusService and provide different implementations of focus() based on AppModuleBrowser and AppModuleServer. I'm not sure of the fine details of how that would work but it may be the only way to achieve this without using nativeElement at this time.
Upvotes: 3
Reputation: 527
Also you can use selectRootElement method of Renderer2.
For example:
constructor(private renderer: Renderer2) {}
this.renderer.selectRootElement('#domElementId').focus()
, where domElementId is id='domElementId' in your html
Upvotes: 15
Reputation: 71891
The invokeElementMethod
is deprecated, and will not find its way back into the new renderer. To set focus to an element, you can simply use this now:
element.nativeElement.focus();
If you are using document.querySelectorAll
, you are doing something not the angular way, and you should find another way to do it. If there is no other way to do it, then the same principle applies. The focus()
method is plain javascript, so you can use it within angular2/typescript. Be sure to do the querySelectorAll
inside the ngAfterViewInit
hook of the component though:
ngAfterViewInit() {
let inputField: HTMLElement = <HTMLElement>document.querySelectorAll('.dialog input')[0];
inputField && inputField.focus();
}
Upvotes: 20
Reputation: 355
template reference variable :#inlineEditControl
<input #inlineEditControl class="form-control form-control-lg" [placeholder]="label">
@ViewChild('inlineEditControl') inlineEditControl: ElementRef; // input DOM element
this.inlineEditControl.nativeElement.focus();
Upvotes: 6