Angular2 - 将文本框集中在组件加载上

Angular2 - Focusing a textbox on component load

我正在使用 Angular2 (Beta 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>

有关如何设置焦点,请参见

对于 "on load" 使用 ngAfterViewInit() 生命周期回调。

此答案的灵感来自 post

在 Angular2 中将焦点设置在 Html 元素上的步骤

  1. 在您的组件中导入 ViewChildren

    import { Input, Output, AfterContentInit, ContentChild,AfterViewInit, ViewChild, ViewChildren } from 'angular2/core';
    
  2. 为要为其设置焦点的 html 声明局部模板变量名称

  3. 实现函数 ngAfterViewInit() 或其他适当的生命周期挂钩
  4. 下面是我用来设置焦点的一段代码

    ngAfterViewInit() {vc.first.nativeElement.focus()}
    
  5. #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>

最初的问题要求一种方法来最初设置焦点,或者稍后设置焦点,以响应事件。似乎解决这个问题的正确方法是制作一个可以为任何输入元素设置的属性指令,然后使用自定义事件安全地触发此输入元素上的焦点方法。为此,首先创建指令:

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', []);
        });
    }
}

请注意,它在 nativeElement 上使用 renderer.invokeElementMethod,这是网络工作者安全的。另请注意,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] 属性,并且我们将此 EventEmitter 声明为新的 EventEmitter 的输入指令并在我们传递给订阅此事件的箭头函数中调用焦点方法,输入元素将在组件初始化后获得焦点,并且每当调用 setFocus 时。

我在自己的应用程序中也有同样的需求,而且效果如广告所示。非常感谢以下内容:http://blog.thecodecampus.de/angular-2-set-focus-element/

使用简单的 autofocus HTML5 属性适用于 'on load' 场景

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

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

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

我遇到了一个稍微不同的问题。我在 modal 中处理输入,这让我发疯。没有一个建议的解决方案对我有用。

直到我发现这个问题:https://github.com/valor-software/ngx-bootstrap/issues/1597

这位好心人给了我提示,ngx-bootstrap modal 有一个焦点配置。如果此配置未设置为 false,模态框将在动画后聚焦,无法聚焦其他任何东西。

更新:

要设置此配置,请将以下属性添加到模式 div:

[config]="{focus: false}"

更新 2:

为了强制将焦点放在输入字段上,我编写了一个指令并在每个 AfterViewChecked 周期中设置焦点,只要输入字段具有 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() }}

这是最好和最简单的方法,因为代码“myInput.focus()”在输入创建后运行

警告:此解决方案仅在表单中有单个元素时才可接受(用户将无法 select 其他元素)

我对所有浏览器上的许多解决方案都不太满意。这是对我有用的解决方案。

对于路由器更改:

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

然后 ngAfterViewInit() 用于加载场景。

此外,它可以像这样动态完成...

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

Where input is

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

自动对焦第一个字段的指令

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();
    }
  }
}

你可以使用 $ (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();
    }
    }