关注新添加的输入元素

我有一个新的角度2应用程序与 input框清单。当用户点击返回键,我添加一个新的 input框后,他们当前正在编辑的立即。或者更确切地说,我(异步地)向模型中的数组中添加一个新条目,这将导致角度2在不久的将来自动生成一个新的 input框。

如何使 input的焦点自动转移到新添加的元素?

编辑1:
或者,我得到一个对模型对象的引用,这个模型对象导致了 DOM 的生成。从组件代码中,是否有一种方法来搜索表示特定模型对象的 DOM 元素?

编辑2:
这是我的代码,让这个工作。希望这足够冒犯到一些 Angular 2开发者,以鼓励回复: -)

app.WordComponent = ng.core
.Component({
selector: 'word-editor',
template:'<input type="text" [value]="word.word" (input)="word.update($event.target.value)" (keydown)="keydown($event)"/>',
styles:[
''
],
properties:[
'list:list',
'word:word'
]
})
.Class({
constructor:[
function() {
}
],
keydown:function(e) {
if(e.which == 13) {
var ul = e.target.parentNode.parentNode.parentNode;
var childCount = ul.childNodes.length;


this.list.addWord("").then(function(word) {
var interval = setInterval(function() {
if(childCount < ul.childNodes.length) {
ul.lastChild.querySelector('input').focus();
clearInterval(interval);
}
}, 1);
});
}
}
});
94837 次浏览

看看 ViewChild这是 例子。 这可能就是你要找的:

import {Component, ViewChild} from 'angular2/core'


@Component({
selector: 'my-app',
providers: [],
template: `
<div>
<input #name>
</div>
`,
directives: []
})
export class App {


@ViewChild('name') vc: ElementRef;


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

如果我被允许这样做,我将采取@Sasxa 答案的一部分,并修改它,使它更像你正在寻找的。

一些变化

  • 我将使用 ngFor,因此 angular2添加新的输入,而不是自己做。主要目的就是让 angular2在它上面迭代。
  • 我将使用返回具有 changes属性的 查询列表ViewChildren来代替 ViewChild。这个属性是一个可观察的属性,它在元素发生变化后返回元素。

因为在 ES5中,我们没有装饰器,所以我们必须使用 queries属性来使用 ViewChildren

组件

Component({
selector: 'cmp',
template : `
<div>
// We use a variable so we can query the items with it
<input #input (keydown)="add($event)" *ngFor="#input of inputs">
</div>
`,
queries : {
vc : new ng.core.ViewChildren('input')
}
})

将焦点 放在最后一个元素上。

ngAfterViewInit: function() {


this.vc.changes.subscribe(elements => {
elements.last.nativeElement.focus();
});


}

如前所述,ViewChildren 返回包含 changes属性的 QueryList。当我们每次订阅它时,它都会返回元素列表。列表 elements包含一个 last属性(以及其他属性) ,在本例中返回最后一个元素,我们对它使用 nativeElement,最后使用 focus()

添加输入元素 这纯粹是为了方便起见,输入数组除了重新绘制 ngFor之外没有其他实际用途。

add: function(key) {
if(key.which == 13) {
// See plnkr for "this.inputs" usage
this.inputs.push(this.inputs.length+1);
}
}

我们在数组上推入一个 笨蛋项,以便它重新绘制。

示例使用 ES5: http://plnkr.co/edit/DvtkfiTjmACVhn5tHGex

示例使用 ES6/TS: http://plnkr.co/edit/93TgbzfPCTxwvgQru2d0?p=preview

2016年3月29日更新

时间已经过去,事情已经澄清,总是有最好的实践来学习/教授。我通过改变一些东西简化了这个答案

  • 我没有使用 @ViewChildren并订阅它,而是制作了一个指令,每次创建新输入时都会启动该指令
  • 我使用 Renderer来使它成为安全的 WebWorker。最初的答案是直接在 nativeElement上访问 focus(),这是不鼓励的。
  • 现在我听 keydown.enter,它简化了向下键事件,我不必检查 which值。

说到点子上了。这个组件看起来像(下面 plnkrs 中的简化完整代码)

@Component({
template: `<input (keydown.enter)="add()" *ngFor="#input of inputs">`,
})


add() {
this.inputs.push(this.inputs.length+1);
}

还有指令

@Directive({
selector : 'input'
})
class MyInput {
constructor(public renderer: Renderer, public elementRef: ElementRef) {}


ngOnInit() {
this.renderer.invokeElementMethod(
this.elementRef.nativeElement, 'focus', []);
}
}

正如您所看到的,我调用 invokeElementMethod来触发元素上的 focus,而不是直接访问它。

这个版本比原来的要干净和安全得多。

Plnkrs 升级到 Beta 12

示例使用 ES5: http://plnkr.co/edit/EpoJvff8KtwXRnXZJ4Rr

示例使用 ES6/TS: http://plnkr.co/edit/em18uMUxD84Z3CK53RRe

2018年最新情况

不推荐使用 invokeElementMethod。请使用 Renderer2而不是 Renderer。

给你的元素一个 id,你就可以使用 SelectRootElement:

this.renderer2.selectRootElement('#myInput').focus();

您可以实现一个简单的输入文本指令,这样无论何时创建新输入,它都会自动对焦。在视图完全初始化之后,在 ngAfterViewInit()组件生命周期钩子内部调用 focus()方法。

@Directive({
selector: 'input[type=text]'
})
export class FocusInput implements AfterViewInit {
private firstTime: bool = true;
constructor(public elem: ElementRef) {
}


ngAfterViewInit() {
if (this.firstTime) {
this.elem.nativeElement.focus();
this.firstTime = false;
}
}
}

在组件中使用 FocusInput指令:

@Component({
selector: 'app',
directives: [FocusInput],
template: `<input type="text" (keyup.enter)="last ? addNewWord():0"
*ngFor="#word of words; #last = last" [value]="word.word"
#txt (input)="word.word = txt.value" />\{\{words |json}}`
})
export class AppComponent {
words: Word[] = [];
constructor() {
this.addNewWord();
}
addNewWord() {
this.words.push(new Word());
}
}

请注意:

  1. (keyup.enter)事件用于检测按下 < enter > 键时的情况
  2. ngFor用于重复 words数组中每个单词的输入元素
  3. last是一个绑定到局部变量的布尔值,当输入为最后一个时为 true
  4. Keyup 事件绑定到表达式 last ? addNewWord() : 0。这样可以确保只有在从最后一个 Input 按下 < enter > key 时才添加新的输入字段

演示 Plnkr

为了确定在同一周期初始化多个指令时哪个元素将获得重点关注的优先顺序,请使用:

指令:

@Directive({
selector: '[focusOnInit]'
})
export class FocusOnInitDirective implements OnInit, AfterViewInit {
@Input('focusOnInit') priority: number = 0;


static instances: FocusOnInitDirective[] = [];


constructor(public renderer: Renderer, public elementRef: ElementRef) {
}


ngOnInit(): void {
FocusOnInitDirective.instances.push(this)
}


ngAfterViewInit(): void {
setTimeout(() => {
FocusOnInitDirective.instances.splice(FocusOnInitDirective.instances.indexOf(this), 1);
});


if (FocusOnInitDirective.instances.every((i) => this.priority >= i.priority)) {
this.renderer.invokeElementMethod(
this.elementRef.nativeElement, 'focus', []);
}
}
}

用法:

<input type="text" focusOnInit="9">

Https://plnkr.co/edit/t9vdpiwrvsz6mpxcdlxf

使用内联角度代码,条件绘制后的焦点:

  <span *ngIf="editId==item.id">
<input #taskEditText type="text" [(ngModel)]="editTask" (keydown.enter)="save()" (keydown.esc)="saveCancel()"/>
<button (click)="save()">Save</button>
<button (click)="saveCancel()">Cancel</button>
\{\{taskEditText.focus()}}
</span>