我有一个新的Angular 2应用程序,其中包含一个输入框列表。当用户点击返回键时,我会在他们当前正在编辑的输入框之后立即添加一个新输入框。或者更确切地说,我(异步)在模型中向数组添加一个新条目,这会导致Angular 2在不久的将来自动生成一个新的输入框。
如何使输入焦点自动更改为新添加的元素?
[edit]或者,我得到一个模型对象的引用,该对象导致生成DOM。从组件代码中,有没有办法搜索表示特定模型对象的DOM元素?
[edit]这是我的代码,让我的工作。希望这对一些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);
});
}
}
});
答案 0 :(得分:96)
如果我允许这样做,我会参与@Sasxa的答案并对其进行修改,使其更像您正在寻找的内容。
一些变化
ngFor
,因此angular2添加新输入而不是自己做。主要目的是让angular2迭代它。ViewChild
我将使用返回QueryList属性为changes
的ViewChildren
。此属性是一个Observable,它会在元素发生更改后返回。由于在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()
添加输入元素这是纯粹的Convenince,输入数组没有真正的目的,只能重绘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
时间已经过去,事情已经澄清,并且始终有学习/教学的最佳实践。我通过改变一些事情来简化这个答案
@ViewChildren
订阅它,而是每次创建新输入时都会制定一个指令Renderer
使其保持WebWorker安全。原始答案会直接在focus()
上访问nativeElement
,但不鼓励这样做。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已更新至测试版12
使用ES5的示例:http://plnkr.co/edit/EpoJvff8KtwXRnXZJ4Rr
使用ES6 / TS的示例:http://plnkr.co/edit/em18uMUxD84Z3CK53RRe
invokeElementMethod
已弃用。使用Renderer2而不是Renderer。
为您的元素提供ID,您可以使用selectRootElement:
this.renderer2.selectRootElement('#myInput').focus();
答案 1 :(得分:40)
看看ViewChild,这里是example。 这可能是您正在寻找的:
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();
}
}
答案 2 :(得分:22)
使用内联角度代码,在条件绘制后聚焦:
<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>
答案 3 :(得分:9)
您可以实现一个简单的输入文本指令,这样无论何时创建新输入,它都会自动对焦。视图完全初始化后,focus()
组件生命周期挂钩内部会调用ngAfterViewInit()
方法。
@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());
}
}
请注意以下事项:
(keyup.enter)
事件用于检测何时&lt; enter&gt;按键ngFor
用于重复words
last
是绑定到局部变量的布尔值,当输入是最后一个时,该值为true last ? addNewWord() : 0
。这确保仅在&lt; enter&gt;时添加新的输入字段。从最后一个输入答案 4 :(得分:3)
为了在同一周期初始化多个指令时优先考虑哪个元素会得到关注,请使用:
<强>指令:强>
@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">