Я пытаюсь установить фокус на любой заданный вход после того, как этот вход изменится (или потенциально манипулировать тем же элементом DOM другими способами). Я использую Reactive Forms, и элементы Form отображаются динамически.
Проблема, с которой я столкнулся, заключается в том, что я могу получить доступ к элементу, который был изменен, либо с помощью @ViewChildren(AppTag) ipt!: QueryList<AppTag>
, что позволяет мне фильтровать нужный элемент,но тогда я не знаю, как получить этот элемент, используя nativeElement
, или я могу использовать @ViewChildren(AppTag) ipt!: QueryList<ElementRef>
, что (удивительно), кажется, позволяет мне фильтровать рассматриваемый элемент, но (также удивительно), я все еще не могуманипулировать элементом DOM. В любом случае я получаю ошибку: "itm.nativeElement is undefined"
.
Чтобы воспроизвести ошибку, введите любое значение в один из Inputs
в следующем StackBlitz , а затем TAB
outзаписи. Вы увидите ошибку в консоли.
Ниже приведены соответствующие фрагменты кода, но, пожалуйста, поэкспериментируйте с полным примером StackBlitz, чтобы более четко увидеть шаблон и структуру данных:
app.component.ts
export class AppComponent implements OnInit {
@ViewChildren(AppTag) ipt !: QueryList<ElementRef>
name = 'Angular';
formCtls: any = {};
form: FormGroup = new FormGroup({});
data: {} = { // raw data
name:
{
first: {values: [""], label: "first name"},
middle: {values: [""], label: "middle name"},
last: {values: [""], label: "last name"}
}
};
dispData: any[] = []; // Data formatted for display/iteration by template
itmNo: number = 0; // Unique ID for each Input
focusItm = 0; // The bridge by which "FormControl.valueChanges" communicates with "QueryList.changes"
. . .
. . .
ngAfterViewInit() {
this.ipt.changes.subscribe(list=>{
setTimeout(()=>
list.filter(itm=>+itm.id===this.focusItm).forEach(itm=>{
console.log(`Item: ${itm.id} Focus: ${this.focusItm} ${+itm.id===this.focusItm}`);
itm.nativeElement.focus(); // <-- HERE'S WHERE I'M HAVING THE TROUBLE
}
),0)}
)
}
. . .
. . .
renderDisplayArray(){
this.dispData = [];
this.itmNo = 0;
. . .
. . .
const i=r;
this.formCtls[ctlName] = new FormControl(itm["values"][r], {updateOn: 'blur'});
this.form.addControl(ctlName,this.formCtls[ctlName]);
const curItm=this.itmNo;
this.formCtls[ctlName].valueChanges.subscribe(val=>{
console.log(`VALUE: ${val}`);
itm["values"][i]=val || '';
this.renderDisplayArray();
this.focusItm = curItm;
})
. . .
. . .
Вот директива AppTag
, которую я применяю к входам, чтобы иметь возможность filter
и захватывать нужные мне элементы DOM. appTag.ts
import { Component, Directive, ElementRef, OnInit, Input } from "@angular/core";
@Directive({
selector: '[appTag]'
})
export class AppTag implements OnInit{
constructor(private el: ElementRef) {}
@Input('appTag') id: number;
}