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

时间:2018-12-21 20:00:49

标签: angular angular-reactive-forms

我正在尝试创建一个输入表单,其中输入的标签和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" }

2 个答案:

答案 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