Angular 2 Set focus on first field of form on component load
Solution 1
You should use an directive to achieve this behavior.
This will show you the way how to do it: https://plnkr.co/edit/ttxCP7vCLkLtNb3Xiaah?p=preview
import {Component, NgModule, Directive, ElementRef, Renderer} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
@Directive({
selector: 'form[anyNameHere]'
})
export class SelectFirstInputDirective {
constructor(private _eRef: ElementRef, private _renderer : Renderer) { }
private _getInputElement(nativeElement: any): any {
if (!nativeElement || !nativeElement.children) return undefined;
if (!nativeElement.children.length && nativeElement.localName === 'input' && !nativeElement.hidden) return nativeElement;
let input;
[].slice.call(nativeElement.children).every(c => {
input = this._getInputElement(c);
if (input) return false; // break
return true; // continue!
});
return input;
}
ngAfterViewInit() {
let formChildren = [].slice.call(this._eRef.nativeElement.children);
formChildren.every(child => {
let input = this._getInputElement(child);
if (input) {
this._renderer.invokeElementMethod(input, 'focus', []);
return false; // break!
}
return true; // continue!
});
}
}
@Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<form anyNameHere>
<div class="form-group">
<input hidden formcontrolname="firstName" type="text" class="form-control input-sm ng-pristine ng-valid ng-touched" placeholder="First Name" id="firstName">
<label class="col-sm-3 control-label" for="firstName">Name</label>
<div class="col-sm-9 form-inline">
<div class="form-group">
<div class="col-sm-12">
<input formcontrolname="firstName" type="text" class="form-control input-sm ng-pristine ng-valid ng-touched" placeholder="First Name" id="firstName">
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<input formcontrolname="lastName" type="text" class="form-control input-sm ng-untouched ng-pristine ng-valid" placeholder="Last Name" id="lastName">
</div>
</div>
</div>
</div>
</form>
</div>
`,
})
export class App {
constructor() {
this.name = 'Angular2'
}
}
@NgModule({
imports: [ BrowserModule ],
declarations: [ App, SelectFirstInputDirective ],
bootstrap: [ App ]
})
export class AppModule {}
Solution 2
you can achieve this by simply adding the "autofocus" attribute to your input element like.
<input class="form-control" [formControl]="name" autofocus>
Solution 3
HTML autofocus attribute do exactly that
<input type="text" name="fname" autofocus>
Solution 4
With Angular 4,Renderer has been deprecated, so the directive way is gone. But anyhow you can always use a "quick and dirty" way: add the reference to the element you want to set focus on and just use <reference-name>.focus()
<form [formGroup]="form" (ngSubmit)="onSubmit(form, $event); needFocus.focus()">
<input placeholder="" formControlName="name" #needFocus>
</form>
Naveed Ahmed
Updated on July 14, 2021Comments
-
Naveed Ahmed almost 3 years
In my app I want to automatically set focus on first field of form on component load. Can anyone please guide how to achieve this without any repetition as I want this on every form (Reactive Forms) in my app.
-
Naveed Ahmed over 7 yearsThank you so much @mxii. Apparently the above directive should set the focus on first input field in the form and it does it in the plunker. But when I tested it in my app it didn't work, probably because in my case the input field is under a div tag. Is there any way to query and select the input elements only and then set focus to first input. Currently you are using this._eRef.nativeElement.children which selects all children of the form.
-
slaesh over 7 yearsSee my updated answer/plunker.. you need to do a recursive search! :)
-
Naveed Ahmed over 7 yearsStill no success, I logged, value of input after this line in directive and let input = this._getInputElement(child); and its undefined. Please have a look at plnkr.co/edit/YF7M4ph7891x03hjJr6A?p=preview
-
Naveed Ahmed over 7 yearsPlease also guide how to skip the hidden inputs? Since if the first input is hidden it would set focus to that, which isn't visible on screen.
-
Naveed Ahmed over 7 yearsOne more thing, Angular team sdiscourage the use of ElementRef this is what I found in comments "Use this API as the last resort when direct access to DOM is needed. Use templating and data-binding provided by Angular instead. Alternatively you take a look at {@link Renderer} which provides API that can safely be used even when direct access to native elements is not supported." Relying on direct DOM access creates tight coupling between your application and rendering layers which will make it impossible to separate the two and deploy your application into a web worker.
-
slaesh over 7 yearsMy fault, updated! And its now checking the hidden property.. you are right, but we are using the
Render
here !! It should be the last resort to MANIPULATE with ElementRef, not to check those childs and so on.. -
Naveed Ahmed over 7 yearsThank you so much @mxii but it work sometimes and sometimes it doesnt work. Please have a look at plnkr.co/edit/vvdq8IMsGjDAAM2YiO1P?p=preview
-
slaesh over 7 yearsCause in that example you are using
type="hidden"
instead of the attributehidden
!! See this plunker: plnkr.co/edit/azdVcdRSgER13qAcM97a?p=preview I just pointed you to the idea, everything else is now your job! ;) -
Naveed Ahmed over 7 yearsThank you so much mxii that was really helpful. Actually I was not sure what other properties does nativeElement support. localName, hidden and type seems to cover all cases. I added support for select and text area as well :)
-
William Gaul over 7 yearsDefinitely works but wow what bloat just to set focus of an input!
-
Nikhil Radadiya over 6 years@mxii it works when page reload, but doesn't work without reload, M I doing something wrong?
-
gentiane over 6 yearsThe input will get the focus only after the page is loaded. But if you navigate in your application and return of the page, then the input will not longer receive focus. autofocus is not well adapted for single page application.
-
Rajiv over 5 yearsyou can create a ref to your input in the view <input #myname> and then you can access it in your component class @ViewChild('myname') input; ngAfterViewInit() { this.input.focus; }
-
pcnate over 4 yearsthis is only useful when you are hard coding your inputs rather than dynamically generating with ngFor
-
Faizan Saiyed over 3 yearsThanks it works for inputs but this does not focuses textarea. Can you please update for textarea also?
-
slaesh over 3 years@faizan Just replace the
.localName === 'input'
to'textarea'