如何从静态数组而不是动态用户输入中设置FormControl名称



我正在尝试创建一个输入表单,其中输入的标签和FormControl名称来自模型中定义的对象数组,而不是根据用户操作动态生成每个新输入。我看到的所有示例都是针对用户单击按钮添加新输入的场景,但在我的用例中没有看到任何示例。

我试着在这里使用官方Angular指南中的例子,以及我在其他地方搜索到的许多例子,但我不知道如何将信息正确地推送到FormArray上。标签填充正确,输入数量正确,但模型和视图之间的绑定没有发生。这是我得到的最接近的:

TypeScript:

import { FormGroup, FormControl, FormBuilder, FormArray, Validators } from '@angular/forms';
export class LabFormComponent implements OnInit {
specimenControls: FormArray;
constructor(
private router: Router,
private formBuilder: FormBuilder
) { }
async ngOnInit() {
await this.addSpecimens();
}
specimens = [
{ label: "SST: ", name: "sst" },
{ label: "LAV: ", name: "lav" },
{ label: "BLUE: ", name: "blue"}
];
specimenFields : FormGroup = this.formBuilder.group({
specimenControls: this.formBuilder.array([
]) 
});
addNewFormControl(specimen) {
const control = <FormArray>this.specimenFields.controls['specimenControls'];
control.push(this.formBuilder.control(specimen));
}
addSpecimens() {
for(let specimen of this.specimens) {
this.addNewFormControl(specimen);
}
}

HTML:

<div>
<form [formGroup]="specimenFields" (ngSubmit)="addSpecs();showSpecForm=false">
<div formArrayName="specimenControls">
<div *ngFor="let specimen of specimens; let i=index" style="margin-bottom:10px">
<label class="form-label">{{specimen.label}}</label> 
<input matInput class="form-textbox" type="text" [formControlName]="i" maxlength="2" size="2" value="0"/>
<button mat-raised-button style="margin-left:15px;" (click)="decNumber(this.value)" color="primary">-</button>
<button mat-raised-button style="margin-left:10px;" (click)="incNumber(this.value)" color="primary">+</button>
</div>
</div>
<button mat-raised-button type="submit" color="primary">Submit</button>
</form>
</div>

我希望每个动态生成的输入都有一个双向绑定,但我得到的错误是:"Cannot find control with path: 'specimenControls -> 0'"我到处都查过这个错误,但正如我之前提到的,我看到的所有场景都是针对用户单击按钮添加新输入的情况。如果我在addNewFormControl()方法中使用console.log(control),我可以看到FormControl对象,所以我知道"发生了什么",但我不知道为什么它没有看到。例如:

{…}
_onCollectionChange: function _onCollectionChange()
_onDisabledChange: Array []
_parent: Object { pristine: true, touched: false, status: "VALID", … }
asyncValidator: null
controls: (3) […]
0: {…}
_onChange: Array []
_onCollectionChange: function _onCollectionChange()
_onDisabledChange: Array []
_parent: Object { pristine: true, touched: false, status: "VALID", … }
​​​_pendingValue: Object { label: "SST: ", name: "sst" }
asyncValidator: null
errors: null
pristine: true
status: "VALID"
statusChanges: Object { _isScalar: false, closed: false, isStopped: false, … }​​​
touched: false​​​
validator: null
value: Object { label: "SST: ", name: "sst" }

我看不出你在哪里创建FormControl?

尝试更改:

control.push(this.formBuilder.control(specimen));

对此:

control.push(new FormControl(specimen.name));

这也起作用:

control.push(this.formBuilder.control(specimen.name));

我在这里做了一个堆叠:https://stackblitz.com/edit/angular-w4q1w1

我上周的帖子似乎被删除了,因为它缺乏对stackblitz示例的适当介绍。所以,它又来了:

当你说"设置FormControl名称"时,我假设你想用模型中的数组数据构建表单,而不是在表单构建后直接重命名控件。

从模型数据构建表单的一种方法是迭代数组,使用每个项上的字符串(或转换为字符串的属性)作为控件名称。我建议使用FormGroup而不是FormArray,因为FormArray隐式地使用其每个FormControl的序号作为名称。因此,不能用传统方法在FormArray中命名FormControls。

我进一步建议在OnInit()Angular生命周期挂钩期间构建FormGroup。它在组件构建之后运行,考虑到在组件构建之前数组数据作为@Input传入的情况。如果您使用的@Input数据在其组件构建后才定义,则需要使用OnChanges()钩子。

form: FormGroup;
ngOnInit() {
this.form = this.buildForm();
}
buildForm(): FormGroup {
const group = new FormGroup({});
this.specimens.forEach((specimen: any) => {
group.addControl(specimen.name, new FormControl());
})
return group;
}

查看此stackblitz以获取完整示例:https://stackblitz.com/edit/angular-dbt5f3

最新更新