我正在尝试创建一个输入表单,其中输入的标签和FormControl名称来自模型中定义的对象数组,而不是根据用户操作动态生成每个新输入。我看到的所有示例都是针对用户单击按钮以添加新输入的情况,但在我的用例中看不到任何示例。
我尝试使用官方Angular指南here中的示例,但在其他地方搜索时发现了很多示例,但是我无法弄清楚如何将信息正确正确地推送到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" }
答案 0 :(得分:1)
我在创建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
答案 1 :(得分:0)
好像我上周的帖子被删除了,因为它没有对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