Angular2 - 将文本框集中在组件加载上
Posted
技术标签:
【中文标题】Angular2 - 将文本框集中在组件加载上【英文标题】:Angular2 - Focusing a textbox on component load 【发布时间】:2016-06-17 19:58:35 【问题描述】:我正在使用 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>
【问题讨论】:
【参考方案1】:有关如何设置焦点,请参阅Angular 2: Focus on newly added input element。
对于“加载”,使用ngAfterViewInit()
生命周期回调。
【讨论】:
非常感谢。您分享的链接很有帮助。为此+1。将分享这个特定场景的答案。【参考方案2】:这个答案的灵感来自帖子Angular 2: Focus on newly added input element
在 Angular2 中将焦点设置在 Html 元素上的步骤
在组件中导入 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>
【讨论】:
很简单,但是如果您需要在另一个组件中设置焦点怎么办?例如,来自子组件的默认搜索框(在标题中)。 动态生成的元素怎么样? 使用 Angular Material 我需要在构造函数中包含ChangeDetectorRef
,然后在焦点调用之后调用this.cd.detectChanges();
,根据this answer by @jspassov。【参考方案3】:
最初的问题要求一种方法来最初设置焦点,或者稍后设置焦点,以响应事件。似乎解决这个问题的正确方法是制作一个可以为任何输入元素设置的属性指令,然后使用自定义事件安全地触发该输入元素上的焦点方法。为此,首先创建指令:
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 组件,该组件具有您希望使用新指令将焦点设置到输入元素的模板:
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 方法,输入元素将在组件初始化后以及每当调用 setFocus 时获得焦点。
我在自己的应用程序中也有同样的需求,这与宣传的一样有效。非常感谢以下:http://blog.thecodecampus.de/angular-2-set-focus-element/
【讨论】:
这很好,而且很有效,但我想知道对于一个小焦点来说,这是否只是一点点太多的工作。我本来打算为用户做一件好事,因为这不是必需的,但似乎为节省用户单击而编写了过多的代码。 @KentWeigel - 这是一个非常经典的解决方案,而且效果很好。这是imo的“正确”答案。谢谢。 这是一个非常好的解决方案,但你没有使用setFocus
函数【参考方案4】:
使用简单的autofocus
HTML5 属性适用于“加载”场景
<input autofocus placeholder="enter text" [(ngModel)]="test">
或
<button autofocus (click)="submit()">Submit</button>
http://www.w3schools.com/TAgs/att_input_autofocus.asp
【讨论】:
这似乎只有在您刷新页面或从头开始加载页面时才有效。如果您通过路由器导航到表单组件,则不会选择该字段。 当我们有多个组件时,这不是一个好的解决方案,这仅适用于第一个默认组件 +1 - 谢谢 Nikhil,非常完美;我这样使用它: value.name :点击div,输入下方立即获得焦点,之前没有。不得不再次点击进入并输入,这是一个“中途”。一键左键!【参考方案5】:我遇到了一个稍微不同的问题。我在 modal 中处理输入,这让我发疯。没有任何建议的解决方案对我有用。
直到我发现这个问题:https://github.com/valor-software/ngx-bootstrap/issues/1597
这个好人给了我提示 ngx-bootstrap modal 有一个焦点配置。如果此配置未设置为 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', []);
【讨论】:
嗨@FireGnome,你能分享在哪里配置这个吗? 如您在此处看到的:valor-software.com/ngx-bootstrap/#/modals#static 有一个配置属性 [config]="backdrop: 'static'" 您可以在此处设置属性焦点:false 嗨,我有同样的问题,我已经添加了 ngx 模式和配置,并尝试使用指令添加焦点(还没有运气),你用什么来为输入添加焦点每一次 ?谢谢【参考方案6】:<input id="name" type="text" #myInput />
myInput.focus()
这是最好和最简单的方法,因为代码“myInput.focus()”在输入创建后运行
警告:仅当表单中有单个元素时,此解决方案才可接受(用户将无法选择其他元素)
【讨论】:
哈哈,这确实有效!有点hacky但非常简单实用,谢谢!:) 一开始我非常喜欢它,但它似乎总是让我无法选择其他元素(甚至无法突出显示要复制的文本)。必须在查看孩子的情况下切换到此处接受的答案。 是的,如果屏幕上只有一个编辑,则此方法可以接受。它可以防止将焦点放在任何其他输入上! 请注意,myInput.focus() 方法将在每个更改周期触发。这可能会导致像@JasonW 所述的不良行为。 隐藏的宝石!!:) 你摇滚我的朋友!【参考方案7】:我对所有浏览器上的许多这些解决方案都不太满意。这是对我有用的解决方案。
对于路由器更改:
router.events.subscribe((val) =>
setTimeout(() =>
if (this.searchElement)
this.searchElement.nativeElement.focus();
, 1);
)
然后ngAfterViewInit()
用于加载场景。
【讨论】:
【参考方案8】:另外,它可以像这样动态完成......
<input [id]="input.id" [type]="input.type" [autofocus]="input.autofocus" />
输入在哪里
const input =
id: "my-input",
type: "text",
autofocus: true
;
【讨论】:
相反的对我不起作用[autofocus]="false"
在您的情况下,它将是 autofocus="false"; [] 仅用于“myObj.key”之类的评估。你正在使用一个实际的字符串。【参考方案9】:
autoFocus 第一个字段的指令
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();
【讨论】:
【参考方案10】:你可以使用 $ (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();
【讨论】:
+1 是唯一一个使用@ViewChild 的,但如果你已经获得了对元素(或它的容器)的引用,则不需要 jquery。以上是关于Angular2 - 将文本框集中在组件加载上的主要内容,如果未能解决你的问题,请参考以下文章
在 MS Access 中,创建动态查询后,如何使用记录集中的相应值更新表单上的文本框?