Angular2 - Focusing a textbox on component load

I am developing a component in Angular2 (Beta 8). The component has a textbox and a dropdown. I would like to set the focus in textbox as soon as component is loaded or on change event of dropdown. How would I achieve this in angular2. Following is Html for the component.

<div>
<form role="form" class="form-horizontal ">
<div [ngClass]="{showElement:IsEditMode, hidden:!IsEditMode}">
<div class="form-group">
<label class="control-label col-md-1 col-sm-1" for="name">Name</label>
<div class="col-md-7 col-sm-7">
<input id="name" type="text" [(ngModel)]="person.Name" class="form-control" />


</div>
<div class="col-md-2 col-sm-2">
<input type="button" value="Add" (click)="AddPerson()" class="btn btn-primary" />
</div>
</div>
</div>
<div [ngClass]="{showElement:!IsEditMode, hidden:IsEditMode}">
<div class="form-group">
<label class="control-label col-md-1 col-sm-1" for="name">Person</label>
<div class="col-md-7 col-sm-7">
<select [(ngModel)]="SelectedPerson.Id"  (change)="PersonSelected($event.target.value)" class="form-control">
<option *ngFor="#item of PeopleList" value="{{item.Id}}">{{item.Name}}</option>
</select>
</div>
</div>
</div>
</form>
</div>

136181 次浏览

See Angular 2: Focus on newly added input element for how to set the focus.

For "on load" use the ngAfterViewInit() lifecycle callback.

This answer is inspired by post Angular 2: Focus on newly added input element

Steps to set the focus on Html element in Angular2

  1. Import ViewChildren in your Component

    import { Input, Output, AfterContentInit, ContentChild,AfterViewInit, ViewChild, ViewChildren } from 'angular2/core';
    
  2. Declare local template variable name for the html for which you want to set the focus

  3. Implement the function ngAfterViewInit() or other appropriate life cycle hooks
  4. Following is the piece of code which I used for setting the focus

    ngAfterViewInit() {vc.first.nativeElement.focus()}
    
  5. Add #input attribute to the DOM element you want to access.

///This is typescript
import {Component, Input, Output, AfterContentInit, ContentChild,
AfterViewChecked, AfterViewInit, ViewChild,ViewChildren} from 'angular2/core';


export class AppComponent implements AfterViewInit,AfterViewChecked {
@ViewChildren('input') vc;
  

ngAfterViewInit() {
this.vc.first.nativeElement.focus();
}
  

}
<div>
<form role="form" class="form-horizontal ">
<div [ngClass]="{showElement:IsEditMode, hidden:!IsEditMode}">
<div class="form-group">
<label class="control-label col-md-1 col-sm-1" for="name">Name</label>
<div class="col-md-7 col-sm-7">
<input #input id="name" type="text" [(ngModel)]="person.Name" class="form-control" />


</div>
<div class="col-md-2 col-sm-2">
<input type="button" value="Add" (click)="AddPerson()" class="btn btn-primary" />
</div>
</div>
</div>
<div [ngClass]="{showElement:!IsEditMode, hidden:IsEditMode}">
<div class="form-group">
<label class="control-label col-md-1 col-sm-1" for="name">Person</label>
<div class="col-md-7 col-sm-7">
<select [(ngModel)]="SelectedPerson.Id"  (change)="PersonSelected($event.target.value)" class="form-control">
<option *ngFor="#item of PeopleList" value="\{\{item.Id}}">\{\{item.Name}}</option>
</select>
</div>
</div>
</div>
</form>
</div>

The original question asked for a way to set focus initially, OR to set focus later, in response to an event. It seems like the correct way to approach this is to make an attribute directive which can be set for any input element, and then to use a custom event to safely trigger the focus method on this input element. To to so, first create the directive:

import { Directive, Input, EventEmitter, ElementRef, Renderer, Inject } from '@angular/core';


@Directive({
selector: '[focus]'
})
export class FocusDirective {
@Input('focus') focusEvent: EventEmitter<boolean>;


constructor(@Inject(ElementRef) private element: ElementRef, private renderer: Renderer) {
}


ngOnInit() {
this.focusEvent.subscribe(event => {
this.renderer.invokeElementMethod(this.element.nativeElement, 'focus', []);
});
}
}

Note that it uses renderer.invokeElementMethod on the nativeElement, which is web worker safe. Notice also that focusEvent is declared as an input.

Then add the following declarations to the Angular 2 component which has the template where you wish to use the new directive to set focus to an input element:

public focusSettingEventEmitter = new EventEmitter<boolean>();


ngAfterViewInit() { // ngOnInit is NOT the right lifecycle event for this.
this.focusSettingEventEmitter.emit(true);
}
setFocus(): void {
this.focusSettingEventEmitter.emit(true);
}

Don't forget to import EventEmitter above the component like this:

import { Component, EventEmitter } from '@angular/core';

and in the template for this component, set the new [focus] attribute like this:

<input id="name" type="text" name="name"
[(ngModel)]="person.Name" class="form-control"
[focus]="focusSettingEventEmitter">

Finally, in your module, import and declare the new directive like this:

import { FocusDirective } from './focus.directive';


@NgModule({
imports: [ BrowserModule, FormsModule ],
declarations: [AppComponent, AnotherComponent, FocusDirective ],
bootstrap: [ AppComponent ]
})

To recap: the ngAfterViewInit function will cause the new EventEmitter to emit, and since we assigned this emitter to the [focus] attribute in the input element in our template, and we declared this EventEmitter as an input to the new directive and invoked the focus method in the arrow function that we passed to the subscription to this event, the input element will receive focus after the component is initialized, and whenever setFocus is called.

I had the same need in my own app, and this worked as advertised. Thank you very much to the following: http://blog.thecodecampus.de/angular-2-set-focus-element/

Using simple autofocus HTML5 attribute works for 'on load' scenario

 <input autofocus placeholder="enter text" [(ngModel)]="test">

or

<button autofocus (click)="submit()">Submit</button>

http://www.w3schools.com/TAgs/att_input_autofocus.asp

I had a slightly different problem. I worked with inputs in a modal and it drove me mad. No of the proposed solutions worked for me.

Until i found this issue: https://github.com/valor-software/ngx-bootstrap/issues/1597

This good guy gave me the hint that ngx-bootstrap modal has a focus configuration. If this configuration is not set to false, the modal will be focused after the animation and there is NO WAY to focus anything else.

Update:

To set this configuration, add the following attribute to the modal div:

[config]="{focus: false}"

Update 2:

To force the focus on the input field i wrote a directive and set the focus in every AfterViewChecked cycle as long as the input field has the class ng-untouched.

 ngAfterViewChecked() {
// This dirty hack is needed to force focus on an input element of a modal.
if (this.el.nativeElement.classList.contains('ng-untouched')) {
this.renderer.invokeElementMethod(this.el.nativeElement, 'focus', []);
}
}
<input id="name" type="text" #myInput />
\{\{ myInput.focus() }}

this is the best and simplest way, because code "myInput.focus()" runs after input created

WARNING: this solution is acceptable only if you have single element in the form (user will be not able to select other elements)

I didn't have much luck with many of these solutions on all browsers. This is the solution that worked for me.

For router changes:

router.events.subscribe((val) => {
setTimeout(() => {
if (this.searchElement) {
this.searchElement.nativeElement.focus();
}
}, 1);
})

Then ngAfterViewInit() for the onload scenario.

Also, it can be done dynamically like so...

<input [id]="input.id" [type]="input.type" [autofocus]="input.autofocus" />

Where input is

const input = {
id: "my-input",
type: "text",
autofocus: true
};

Directive for autoFocus first field

import {
Directive,
ElementRef,
AfterViewInit
} from "@angular/core";


@Directive({
selector: "[appFocusFirstEmptyInput]"
})
export class FocusFirstEmptyInputDirective implements AfterViewInit {
constructor(private el: ElementRef) {}
ngAfterViewInit(): void {
const invalidControl = this.el.nativeElement.querySelector(".ng-untouched");
if (invalidControl) {
invalidControl.focus();
}
}
}

you can use $ (jquery) :

<div>
<form role="form" class="form-horizontal ">
<div [ngClass]="{showElement:IsEditMode, hidden:!IsEditMode}">
<div class="form-group">
<label class="control-label col-md-1 col-sm-1" for="name">Name</label>
<div class="col-md-7 col-sm-7">
<input id="txtname`enter code here`" type="text" [(ngModel)]="person.Name" class="form-control" />


</div>
<div class="col-md-2 col-sm-2">
<input type="button" value="Add" (click)="AddPerson()" class="btn btn-primary" />
</div>
</div>
</div>
<div [ngClass]="{showElement:!IsEditMode, hidden:IsEditMode}">
<div class="form-group">
<label class="control-label col-md-1 col-sm-1" for="name">Person</label>
<div class="col-md-7 col-sm-7">
<select [(ngModel)]="SelectedPerson.Id"  (change)="PersonSelected($event.target.value)" class="form-control">
<option *ngFor="#item of PeopleList" value="\{\{item.Id}}">\{\{item.Name}}</option>
</select>
</div>
</div>
</div>
</form>
</div>

then in ts :

    declare var $: any;


@Component({
selector: 'app-my-comp',
templateUrl: './my-comp.component.html',
styleUrls: ['./my-comp.component.css']
})
export class MyComponent  {


@ViewChild('loadedComponent', { read: ElementRef, static: true }) loadedComponent: ElementRef<HTMLElement>;


setFocus() {
const elem = this.loadedComponent.nativeElement.querySelector('#txtname');
$(elem).focus();
}
}