Как программно установить фокус на динамически созданный FormControl в Angular2
Кажется, я не могу сосредоточиться на поле ввода динамически добавленной FormGroup:
addNewRow(){
(<FormArray>this.modalForm.get('group1')).push(this.makeNewRow());
// here I would like to set a focus to the first input field
// say, it is named 'textField'
// but <FormControl> nor [<AbstractControl>][1] dont seem to provide
// either a method to set focus or to access the native element
// to act upon
}
Как настроить фокус на angular2 FormControl или AbstractControl?
Ответы
Ответ 1
Я сделал это сообщение еще в декабре 2016 года, с тех пор Angular значительно продвинулся вперед, поэтому из других источников я убедился, что это все еще законный способ делать вещи
Вы не можете установить FormControl
или AbstractControl
, так как они не являются элементами DOM. Что вам нужно сделать, так это каким-то образом получить ссылку на них и вызвать .focus()
для этого. Этого можно добиться с помощью ViewChildren
(в настоящее время нет документации по API, 2016-12-16).
В классе вашего компонента:
import { ElementRef, ViewChildren } from '@angular/core';
// ...imports and such
class MyComponent {
// other variables
@ViewChildren('formRow') rows: ElementRef;
// ...other code
addNewRow() {
// other stuff for adding a row
this.rows.first().nativeElement.focus();
}
}
Если вы хотите сосредоточиться на последнем ребенке... this.rows.last().nativeElement.focus()
А в вашем шаблоне что-то вроде:
<div #formRow *ngFor="let row in rows">
<!-- form row stuff -->
</div>
EDIT:
Я на самом деле нашел CodePen кого-то, кто делает то, что вы ищете https://codepen.io/souldreamer/pen/QydMNG
Ответ 2
Для Углового 5, объединив все приведенные выше ответы, выполните следующие действия:
Компонентный код:
import { AfterViewInit, QueryList, ViewChildren, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
// .. other imports
export class MyComp implements AfterViewInit, OnDestroy {
@ViewChildren('input') rows: QueryList<any>;
private sub1:Subscription = new Subscription();
//other variables ..
// changes to rows only happen after this lifecycle event so you need
// to subscribe to the changes made in rows.
// This subscription is to avoid memory leaks
ngAfterViewInit() {
this.sub1 = this.rows.changes.subscribe(resp => {
if (this.rows.length > 1){
this.rows.last.nativeElement.focus();
}
});
}
//memory leak avoidance
ngOnDestroy(){
this.sub1.unsubscribe();
}
//add a new input to the page
addInput() {
const formArray = this.form.get('inputs') as FormArray;
formArray.push(
new FormGroup(
{input: new FormControl(null, [Validators.required])}
));
return true;
}
// need for dynamic adds of elements to re
//focus may not be needed by others
trackByFn(index:any, item:any){
return index;
}
Логика шаблона Выглядит так:
<div formArrayName="inputs" class="col-md-6 col-12"
*ngFor="let inputCtrl of form.get('phones').controls;
let i=index; trackBy:trackByFn">
<div [formGroupName]="i">
<input #input type="text" class="phone"
(blur)="addRecord()"
formControlName="input" />
</div>
</div>
В моем шаблоне я добавляю запись размытия, но вы можете так же легко настроить кнопку для динамического добавления следующего поля ввода. Важная часть состоит в том, что с помощью этого кода новый элемент получает фокус по желанию.
Дайте мне знать, что вы думаете
Ответ 3
Это безопасный метод, рекомендуемый угловыми
@Component({
selector: 'my-comp',
template: '
<input #myInput type="text" />
<div> Some other content </div>
'
})
export class MyComp implements AfterViewInit {
@ViewChild('myInput') input: ElementRef;
constructor(private renderer: Renderer) {}
ngAfterViewInit() {
this.renderer.invokeElementMethod(this.input.nativeElement,
'focus');
}
}