In Angular2 how can I set binding on element focus. I don't want to set it with elementRef. I think in AngularJS there is ngFocus directive In Angular2 there is no such directive
9 Answers
Renderer service is now deprecated (as of Angular 4.x) The new Renderer2 service doesn't have the invokeElementMethod. What you can do is to get a reference to the element like this:
const element = this.renderer.selectRootElement('#elementId');
And then you can use that to focus on that element like so:
element.focus();
More on how selectRootElement
works here:
EDIT:
If the element doesn't get focused the common issue is that the element is not ready. (eg.: disabled, hidden etc.). You can do this:
setTimeout(() => element.focus(), 0);
This will create a macrotask that will run in the next VM turn, so if you enabled the element the focus will run properly.

- 970
- 7
- 21
-
1how is the element reference that we get by using renderer2.selectRootElement different from the element reference we get by using ViewChild? I'm trying to understand why using ViewChild to get the element reference (let's say we assign it to 'abc') and then using abc.nativeElement.focus() to set focus on the element poses a XSS security risk but using renderer2 doesn't. – coder101 Apr 22 '19 at 22:26
-
Also, does using nativeElement pose a security risk only when using a component to access an element in its template, or does it also pose a security risk when using it in a custom directive to do the same to an element in any other component's template? – coder101 Apr 22 '19 at 22:29
-
@user6860460 Using renderer2 or any other abstraction provided to you via Angular could be safer because you are not using the DOM directly. However, when you use the nativeElement you opened the risk again. This example is not good for this case. If you were to use the addClass or createElement etc. method of the renderer2 instead of doing it on the raw DOM element, it is considered safer. https://angular.io/api/core/ElementRef read the warning on the bottom. It means you should use the API provided by renderer2 when you can, but once you access the nativeElement it is a risk. – MrBlaise Apr 23 '19 at 11:44
-
But do you open the same risk if you access nativeElement within a Renderer2 method? Thanks. – coder101 Apr 23 '19 at 15:11
-
@user6860460 Technically yes. Once you have the nativeElement you can do whatever you want with it. Like setting the innerHTML parameter directly and inject some code. – MrBlaise Apr 23 '19 at 19:19
-
Then how do you set focus on an element using renderer2 without creating a security risk? Here's what I have: `@ViewChild('referenceVariable') varInputBox; setTimeout(() => {this.renderer.selectRootElement(this.varInputBox.nativeElement).focus();},0);` selectRootElement won't put focus on the element without using the nativeElement property. From what I've read, this is the recommended method to put focus on an element without creating a security risk. – coder101 Apr 23 '19 at 19:41
A simple 'focus' Directive
import {Directive, Input, ElementRef} from 'angular2/core';
@Directive({
selector: '[focus]'
})
class FocusDirective {
@Input()
focus:boolean;
constructor(@Inject(ElementRef) private element: ElementRef) {}
protected ngOnChanges() {
this.element.nativeElement.focus();
}
}
// Usage
@Component({
selector : 'app',
template : `
<input [focus]="inputFocused" type="text">
<button (click)="moveFocus()">Move Focus</button>
`,
directives: [FocusDirective]
})
export class App {
private inputFocused = false;
moveFocus() {
this.inputFocused = true;
// we need this because nothing will
// happens on next method call,
// ngOnChanges in directive is only called if value is changed,
// so we have to reset this value in async way,
// this is ugly but works
setTimeout(() => {this.inputFocused = false});
}
}

- 23,898
- 50
- 191
- 378

- 10,201
- 2
- 15
- 18
-
1A little heads-up. Don't use `nativeElement` directly. This is not save with webworkers. – Poul Kruijt Jul 11 '16 at 13:42
-
1The `directives` property has been removed in RC 6. You should move the `FocusDirective` to declarations property of your NgModule decorator. – cnotethegr8 Mar 30 '17 at 08:39
-
I have the same requirement but, i want to shift the setTimeout inside the directive, can the same functionality be achieved by using setTimeout inside the directive? – abhishek saatal Oct 12 '17 at 09:48
-
This works perfectly for desktop based browsers, but not for mobile based browsers for some reason. Could you see why? – kamal0808 Dec 08 '17 at 03:29
I tried both variants but none is suitable for simple use. 1st (by @AngJobs) needs additional work in component where you use directive (to set focus=true), 2nd (by @ShellZero) not working at all because focus called before the view is actually ready. So I moved focus call to ngAfterViewInit
. Now you can just add <input focus...
and forget it. Element will get focus after view init automatically.
import { Directive, ElementRef, Renderer, AfterViewInit } from '@angular/core';
@Directive({
selector: '[focus]'
})
export class DmFocusDirective implements AfterViewInit {
constructor(private _el: ElementRef, private renderer: Renderer) {
}
ngAfterViewInit() {
this.renderer.invokeElementMethod(this._el.nativeElement, 'focus');
}
}

- 6,999
- 4
- 40
- 55
-
Thanks - this is great. Although your class name doesnt necessarily need prefixing (as you have done with `Dm`). The key bit to apply a prefix to is the selector name value(s). i.e. `selector: '[appFocus]'`. I guess this reduces the likelihood of collisions in subsequent angular versions, etc. – ne1410s Apr 11 '17 at 08:19
-
2Heads up: `Renderer` is deprecated, and the Angular team doesn't plan to bring `invokeElementMethod()` forward into `Renderer2`. https://github.com/angular/angular/issues/13818 – stealththeninja May 22 '17 at 16:46
From @MrBlaise I took the setTimeout snippet which made the following work for me.
<input type="text" #searchInput />
import { ElementRef, ViewChild } from '@angular/core';
...
@ViewChild('searchInput') private searchInput: ElementRef;
...
setTimeout(() => this.searchInput.nativeElement.focus(), 0);

- 3,426
- 5
- 37
- 43
The best way of setting focus on an element with angular2 is by using the Renderer
and invoke an method on the element. There is no way of doing this without elementRef
.
This results in something like this:
this.renderer.invokeElementMethod(this.input.nativeElement, 'focus', []);
Where renderer
gets injected in the constructor using protected renderer : Renderer

- 69,713
- 12
- 145
- 149
-
I think a better approach is to write my own ngFocus directive that manipulate the element and not do it in the component class. – almog Jul 11 '16 at 13:18
-
-
-
1Because everyone would want a slightly different implementation. And this way you can implement it yourself, and learn a little more about angular2 – Poul Kruijt Jul 11 '16 at 13:35
Much more simpler way:
import { Directive, ElementRef, Renderer} from "@angular/core";
@Directive({
selector: "[Focus]"
})
export class myFocus {
constructor(private _el: ElementRef, private renderer: Renderer) {
this.renderer.invokeElementMethod(this._el.nativeElement, 'focus');
}
}

- 4,415
- 12
- 38
- 56
-
Not working for me because focus called before the view is actually ready – Dimanoid Oct 26 '16 at 15:37
-
Then you have to add it in the ngOnInit() [The Angular LifeCycle Hooks] or you have to subscribe to whatever event you have so that "you focus whenever that event has happened". – ShellZero Oct 26 '16 at 16:37
It works for me but have errors in console. After debugging and searching found this article: https://www.picnet.com.au/blogs/guido/post/2016/09/20/angular2-ng2-focus-directive/
Just copy-paste. It worked perfectly for me.
import {Directive, AfterViewInit, ElementRef, DoCheck} from '@angular/core';
@Directive({selector: '[focus]'})
export class FocusDirective implements AfterViewInit, DoCheck {
private lastVisible: boolean = false;
private initialised: boolean = false;
constructor(private el: ElementRef) {
}
ngAfterViewInit() {
console.log('inside FocusDirective.ngAfterViewInit()');
this.initialised = true;
this.ngDoCheck();
}
ngDoCheck() {
console.log('inside FocusDirective.ngDoCheck()');
if (!this.initialised) {
return;
}
const visible = !!this.el.nativeElement.offsetParent;
if (visible && !this.lastVisible) {
setTimeout(() => {
this.el.nativeElement.focus();
}, 1);
}
this.lastVisible = visible;
}
}

- 1,608
- 15
- 8
import { Directive, ElementRef, AfterViewChecked } from '@angular/core';
@Directive({
selector: '[autoFocus]',
})
export class FocusDirective implements AfterViewChecked {
constructor(private _elementRef: ElementRef) { }
ngAfterViewChecked() {
this._elementRef.nativeElement.focus()
}
}

- 550
- 5
- 11
The trick is to use both focus and select together:
this.(element).nativeElement.focus();
this.(element).nativeElement.select();

- 11,199
- 1
- 48
- 63