Ich habe eine neue Angular 2-App mit einer Liste von input
Boxen. Wenn der Benutzer die Eingabetaste drückt, füge ich input
unmittelbar nach dem Feld, das er gerade bearbeitet , ein neues Feld hinzu. Oder besser gesagt, ich füge (asynchron) dem Array im Modell einen neuen Eintrag hinzu, wodurch Angular 2 input
in naher Zukunft automatisch eine neue Box generiert .
Wie kann ich dafür sorgen, dass sich der input
Fokus automatisch auf das neu hinzugefügte Element ändert?
EDIT 1:
Alternativ erhalte ich einen Verweis auf das Modellobjekt, durch das das DOM generiert wird. Gibt es eine Möglichkeit, im Komponentencode nach einem DOM-Element zu suchen, das ein bestimmtes Modellobjekt darstellt?
EDIT 2:
Hier ist mein Code, damit dies funktioniert. Hoffentlich ist dies für einige Angular 2-Entwickler anstößig genug, um eine Antwort zu ermutigen :-)
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);
});
}
}
});
setInterval
solltest höchstwahrscheinlich nur ein seinsetTimeout
.Antworten:
Wenn ich dazu berechtigt bin, nehme ich an der Antwort von @Sasxa teil und ändere sie so, dass sie dem entspricht, wonach Sie suchen.
Ein paar Änderungen
ngFor
so eckiges2 verwenden, das die neue Eingabe hinzufügt, anstatt es selbst zu tun. Der Hauptzweck ist nur, angle2 so zu machen, dass es darüber iteriert.ViewChild
ich das verwendeViewChildren
, wird eine QueryList zurückgegeben, die einechanges
Eigenschaft hat. Diese Eigenschaft ist eine Observable und gibt die Elemente zurück, nachdem sie geändert wurden.Da wir in ES5 keine Dekorateure haben, müssen wir die
queries
Eigenschaft verwenden, um sie zu verwendenViewChildren
Komponente
Konzentrieren Sie sich auf das letzte Element.
ngAfterViewInit: function() { this.vc.changes.subscribe(elements => { elements.last.nativeElement.focus(); }); }
Wie ich bereits sagte, gibt ViewChildren eine QueryList zurück, die eine Eigenschaft enthält
changes
. Wenn wir es bei jeder Änderung abonnieren, wird die Liste der Elemente zurückgegeben. Die Listeelements
enthältlast
(unter anderem) eine Eigenschaft, die in diesem Fall das letzte Element zurückgibt, das wirnativeElement
darauf und schließlich verwendenfocus()
Eingabeelemente hinzufügen Dies ist eine reine Annehmlichkeit. Das Eingabearray hat keinen wirklichen Zweck mehr als das Neuzeichnen des
ngFor
.add: function(key) { if(key.which == 13) { // See plnkr for "this.inputs" usage this.inputs.push(this.inputs.length+1); } }
Wir schieben ein Dummy- Element auf das Array, damit es neu gezeichnet wird.
Beispiel mit ES5: http://plnkr.co/edit/DvtkfiTjmACVhn5tHGex
Beispiel mit ES6 / TS: http://plnkr.co/edit/93TgbzfPCTxwvgQru2d0?p=preview
Update 29/03/2016
Die Zeit ist vergangen, die Dinge wurden geklärt und es gibt immer Best Practices zum Lernen / Lehren. Ich habe diese Antwort vereinfacht, indem ich einige Dinge geändert habe
@ViewChildren
und zu abonnieren, habe ich eine Richtlinie erstellt, die jedes Mal ausgelöst wird, wenn eine neue Eingabe erstellt wirdRenderer
, um WebWorker sicher zu machen. Die ursprüngliche Antwort greiftfocus()
direkt auf die zu, vonnativeElement
der abgeraten wird.keydown.enter
was das Key-Down-Ereignis vereinfacht, ich muss denwhich
Wert nicht überprüfen .Auf den Punkt. Die Komponente sieht aus wie (vereinfachter, vollständiger Code auf den folgenden Plnkrs)
@Component({ template: `<input (keydown.enter)="add()" *ngFor="#input of inputs">`, }) add() { this.inputs.push(this.inputs.length+1); }
Und die Richtlinie
@Directive({ selector : 'input' }) class MyInput { constructor(public renderer: Renderer, public elementRef: ElementRef) {} ngOnInit() { this.renderer.invokeElementMethod( this.elementRef.nativeElement, 'focus', []); } }
Wie Sie sehen, rufe ich
invokeElementMethod
auf, umfocus
das Element auszulösen , anstatt direkt darauf zuzugreifen.Diese Version ist viel sauberer und sicherer als die ursprüngliche.
plnkrs auf Beta 12 aktualisiert
Beispiel mit ES5: http://plnkr.co/edit/EpoJvff8KtwXRnXZJ4Rr
Beispiel mit ES6 / TS: http://plnkr.co/edit/em18uMUxD84Z3CK53RRe
Update 2018
invokeElementMethod
ist veraltet. Verwenden Sie Renderer2 anstelle von Renderer.Geben Sie Ihrem Element eine ID, und Sie können selectRootElement verwenden :
quelle
#input
für mehrere Elemente verwenden können.ngFor
lokale Vorlagenvariable in etwas anderes umbenennen , damit sie nicht so aussieht, als ob sie mit der anderen verwandt wäre#input
:*ngFor="#in of inputs"
.input
, schlage ich vor, ihn auf den zu setzendiv
und das Event in die Luft sprudeln zu lassen :<div (keydown)="add($event)"> <input #input *ngFor="#in of inputs">
.this.renderer2.selectRootElement(this.elementRef.nativeElement).focus();
Schauen Sie sich ViewChild an , hier ein Beispiel . Dies könnte das sein, wonach Sie suchen:
quelle
Mit Inline-Winkelcode nach bedingter Farbe fokussieren:
quelle
Sie können eine einfache Eingabetextanweisung implementieren, sodass sich jede neue Eingabe automatisch fokussiert, wenn sie erstellt wird. Die
focus()
Methode wird innerhalb desngAfterViewInit()
Komponentenlebenszyklus-Hooks aufgerufen, nachdem die Ansicht vollständig initialisiert wurde.Verwenden Sie die
FocusInput
Direktive in Ihrer Komponente:Beachten Sie das Folgende:
(keyup.enter)
Ereignis wird verwendet, um zu erkennen, wann die <Eingabetaste> gedrückt wirdngFor
wird verwendet, um das Eingabeelement für jedes Wort aus dem Array von zu wiederholenwords
last
ist ein Boolescher Wert, der an eine lokale Variable gebunden ist. Dies ist der Fall, wenn die Eingabe die letzte istlast ? addNewWord() : 0
. Dadurch wird sichergestellt, dass ein neues Eingabefeld nur hinzugefügt wird, wenn die <Eingabetaste> von der letzten Eingabe gedrückt wirdDemo Plnkr
quelle
Anguler 5
Vielen Dank!!Verwenden Sie Folgendes, um zu priorisieren, welches Element beim Initialisieren mehrerer Anweisungen im selben Zyklus den Fokus erhält:
Richtlinie:
@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', []); } } }
Verwendung:
https://plnkr.co/edit/T9VDPIWrVSZ6MpXCdlXF
quelle