Angular2 - фокусировка текстового поля на загрузке компонента
Я разрабатываю компонент в Angular2 (бета-версия 8). Компонент имеет текстовое поле и раскрывающийся список. Я хотел бы установить фокус в текстовом поле, как только компонент загружен или при изменении события выпадающего списка. Как бы я достиг этого в angular2. Ниже приведен HTML для компонента.
<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>
7 ответов
Этот ответ вдохновлен постом Angular 2: Фокус на вновь добавленном элементе ввода
Шаги, чтобы установить фокус на элемент HTML в Angular2
Импортируйте ViewChildren в ваш компонент
import { Input, Output, AfterContentInit, ContentChild,AfterViewInit, ViewChild, ViewChildren } from 'angular2/core';
Объявите имя локальной переменной шаблона для HTML, для которого вы хотите установить фокус
- Реализуйте функцию ngAfterViewInit() или другие соответствующие хуки жизненного цикла
Ниже приведен фрагмент кода, который я использовал для установки фокуса
ngAfterViewInit() {vc.first.nativeElement.focus()}
добавлять
#input
атрибут элемента DOM, к которому вы хотите получить доступ.
///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>
Используя простой autofocus
Атрибут HTML5 работает для сценария "под нагрузкой"
<input autofocus placeholder="enter text" [(ngModel)]="test">
или же
<button autofocus (click)="submit()">Submit</button>
<input id="name" type="text" #myInput />
{{ myInput.focus() }}
это лучший и самый простой способ, потому что код "myInput.focus()" запускается после создания ввода
В первоначальном вопросе был задан способ установить фокус вначале, ИЛИ установить фокус позже, в ответ на событие. Кажется, что правильный способ сделать это - создать директиву атрибута, которую можно установить для любого элемента ввода, а затем использовать пользовательское событие для безопасного запуска метода focus на этом элементе ввода. Для этого сначала создайте директиву:
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', []);
});
}
}
Обратите внимание, что он использует renderer.invokeElementMethod для nativeElement, который безопасен для веб-работников. Также обратите внимание, что focusEvent объявлен как вход.
Затем добавьте следующие объявления в компонент Angular 2, который имеет шаблон, в котором вы хотите использовать новую директиву для установки фокуса на элемент ввода:
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);
}
Не забудьте импортировать EventEmitter над компонентом следующим образом:
import { Component, EventEmitter } from '@angular/core';
и в шаблоне для этого компонента установите новый атрибут [focus] следующим образом:
<input id="name" type="text" name="name"
[(ngModel)]="person.Name" class="form-control"
[focus]="focusSettingEventEmitter">
Наконец, в вашем модуле импортируйте и объявите новую директиву следующим образом:
import { FocusDirective } from './focus.directive';
@NgModule({
imports: [ BrowserModule, FormsModule ],
declarations: [AppComponent, AnotherComponent, FocusDirective ],
bootstrap: [ AppComponent ]
})
Напомним: функция ngAfterViewInit приведет к генерации нового EventEmitter, и так как мы присвоили этот эмиттер атрибуту [focus] в элементе input в нашем шаблоне, и мы объявили этот EventEmitter как входные данные для новой директивы и вызвали фокус Метод в функции стрелки, который мы передали подписке на это событие, элемент input будет получать фокус после инициализации компонента и всякий раз, когда вызывается setFocus.
У меня была такая же потребность в моем собственном приложении, и это работало так, как рекламировалось. Большое спасибо следующему: http://blog.thecodecampus.de/angular-2-set-focus-element/
См. Angular 2: Фокус на вновь добавленном элементе ввода, чтобы узнать, как установить фокус.
Для "под нагрузкой" используйте ngAfterViewInit()
жизненный цикл обратного вызова.
Директива для первого поля автофокуса
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();
}
}
}
У меня была немного другая проблема. Я работал с входами в модале, и это сводило меня с ума. Ни одно из предложенных решений не сработало для меня.
Пока я не нашел эту проблему: https://github.com/valor-software/ngx-bootstrap/issues/1597
Этот хороший парень намекнул, что модал ngx-bootstrap имеет конфигурацию фокуса. Если для этой конфигурации не задано значение false, модальное изображение будет сфокусировано после анимации, и НЕТ СПОСОБА фокусировать что-либо еще.
Обновить:
Чтобы установить эту конфигурацию, добавьте следующий атрибут в модальный div:
[config]="{focus: false}"
Обновление 2:
Чтобы наложить фокус на поле ввода, я написал директиву и установил фокус в каждом цикле AfterViewChecked, если в поле ввода есть класс 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]="input.id" [type]="input.type" [autofocus]="input.autofocus" />
Где вход
const input = {
id: "my-input",
type: "text",
autofocus: true
};
Мне не очень повезло со многими из этих решений во всех браузерах. Это решение, которое сработало для меня.
Для изменения маршрутизатора:
router.events.subscribe((val) => {
setTimeout(() => {
if (this.searchElement) {
this.searchElement.nativeElement.focus();
}
}, 1);
})
затем ngAfterViewInit()
для сценария загрузки.
Вы можете использовать $ (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>
затем в 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();
}
}