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


78

我正在开发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>

Answers:


78

使用简单的autofocusHTML5属性可在“加载”情况下使用

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

要么

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

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


45
仅当刷新页面或从头开始加载页面时,这才似乎有效。如果您通过路由器导航到表单组件,则不会选择该字段。
丹尼斯W

3
当我们有多个组件时,这不是一个好的解决方案,这仅适用于第一个默认组件
Paresh Varde

+1-谢谢Nikhil,它很完美;我以这种方式使用它:<div class =“ or-name uk-tile-muted uk-text-left uk-display-block” * ngIf =“ value!== cHttpUser”> {{value.name}} </ div> <input class =“ uk-input uk-form-controls-text or-input” * ngIf =“ value === cHttpUser” [(ngModel)] =“ value.name”自动对焦(click)=“ update( )“(keyup.enter)=” update()“(keyup.tab)=” update()“(blur)=” update()“>:单击div,在下面输入一次即可获得焦点,然后再单击。必须再次单击进入并输入,这是“半途而废”。一键左!
奥利维尔

77

此答案的灵感来自 Angular 2:关注新添加的输入元素

在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>


2
足够简单,但是如果您需要将重点放在另一个组件上怎么办?例如,子组件的默认搜索框(在标题中)。
瑞克·斯特尔

2
动态生成的元素怎么样?
Kaushik Thanki '17年

使用Angular Material,我需要包含ChangeDetectorRef在构造函数中,然后this.cd.detectChanges();在焦点调用之后调用,根据@jspassov的此答案
Derek Hill

29

最初的问题要求一种方法来首先设置焦点,或者稍后再设置焦点以响应事件。看来解决此问题的正确方法是制作一个可以为任何输入元素设置的属性指令,然后使用自定义事件安全地触发此输入元素上的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', []);
        });
    }
}

请注意,它在nativeElement上使用renderer.invokeElementMethod,这对于Web Worker是安全的。还要注意,focusEvent被声明为输入。

然后将以下声明添加到Angular 2组件中,该组件具有您希望在其中使用new指令将焦点设置到输入元素的模板:

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声明为新指令的输入,并调用了focus我们传递给该事件的预订的arrow函数中的方法,在初始化组件之后以及每次调用setFocus时,input元素都会获得焦点。

我在自己的应用程序中也有同样的需求,并且按广告要求工作。非常感谢以下人员:http : //blog.thecodecampus.de/angular-2-set-focus-element/


这很好并且可以工作,但是我想知道这是否只是一个小小的工作,对于次要的关注而言。我本来对用户来说这是一件好事,因为这不是必需的,但是似乎为节省用户一次单击的代码量过多。
Ka Mok

3
@KentWeigel-这是一个非常经典的解决方案,效果很好。这是imo的“正确”答案。谢谢。
HockeyJ

这确实是一个很好的解决方案,但是您没有使用此setFocus功能
HakanFıstık'19

29
<input id="name" type="text" #myInput />
{{ myInput.focus() }}

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


3
哈哈,实际上有效!有点古怪,但是非常简单和实用,谢谢!:)
Wagner Danda da Silva Filho

5
一开始我非常喜欢它,但是似乎它总是使我无法选择其他元素(甚至突出显示要复制的文本)。不得不在这里查看孩子切换到可接受的答案。
杰森W

4
是的,如果屏幕上只有一个编辑,则此方法可以接受。它防止将焦点放在任何其他输入上!
谢尔盖·古林

1
请注意,myInput.focus()方法将在每个更改周期触发。这可能会导致不必要的行为,例如@JasonW所述。
卡斯滕

2
隐藏的宝石!
Manish Jain


2

我有一个稍微不同的问题。我使用模态输入进行工作,这让我发疯。所提出的解决方案均不适合我。

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

这个好人给我的提示是ngx-bootstrap modal具有焦点配置。如果此配置未设置为false,则模态将在动画之后聚焦,并且无法聚焦其他任何东西。

更新:

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

[config]="{focus: false}"

更新2:

为了使焦点集中在输入字段上,我编写了一条指令,并在每个AfterViewChecked周期中设置焦点,只要输入字段具有ng-touched类。

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

嗨@FireGnome,您能分享在哪里配置此设置吗?
Cyber​​abis

如您在此处看到的: valor-software.com/ngx-bootstrap/#/modals#static 有一个配置属性[config] =“ {backdrop:'static'}”您可以在此处设置属性焦点:false
FireGnome

嗨,我遇到了同样的问题,我添加了ngx模态和配置,并尝试通过指令添加焦点(到目前为止还算不上运气),您每次用什么来向输入添加焦点?谢谢
西蒙(Simon)

2

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

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

输入在哪里

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

相反的对我不起作用[autofocus]="false"
teddybear

在您的情况下,它将为autofocus =“ false”; []仅用于“ myObj.key”之类的评估。您使用的是实际字符串。
SoEzPz

1

自动对焦第一场指令

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


0

在所有浏览器上,我对这些解决方案都不满意。这是对我有用的解决方案。

对于路由器更改:

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

然后ngAfterViewInit()是onload场景。


0

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

为使用@ViewChild的唯一对象+1,但是如果您已经有了对该元素(或其容器)的引用,则不需要jquery。
涅米宁
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.