【问题标题】:How do I set FormControl names from a static array rather than from dynamic user input?如何从静态数组而不是动态用户输入设置 FormControl 名称?
【发布时间】:2018-12-21 20:00:49
【问题描述】:

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

我曾尝试使用官方 Angular 指南 here 中的示例以及我在其他地方搜索时发现的许多示例,但我无法弄清楚如何将信息正确推送到 FormArray 上。标签被正确填充并且输入的数量正确,但是模型和视图之间的绑定没有发生。这是我得到的最接近的:

打字稿:

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 -&gt; 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" }

【问题讨论】:

    标签: angular angular-reactive-forms


    【解决方案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

    【讨论】:

    • 据我了解,FormBuilder 类有一个名为 control() 的方法,它等效于 new FormControl(),所以当您执行 private formBuilder: FormBuilderthis.formBuilder.control(_something_) 时,它是同一件事。你知道是不是这样吗?
    • 你是对的。我更新了我的答案。您只需要指定属性,而不仅仅是对象。
    • 啊哈!不是这样,但是您提供的内容使我找到了答案。我没有想到this.formBuilder.control() 的值是设置输入表单的初始值,而不是它的名称。最终我意识到我需要循环的数组不是 my 数组,而是 control's 数组。所以我需要let specimen of specimenFields.controls.specimenControls.controls 而不是let specimen of specimens。我更新了 stackblitz 来说明(虽然我不知道为什么这些值现在是对象而不是“0”),但它适用于我 - 谢谢!
    【解决方案2】:

    看起来我上周的帖子已被删除,因为它缺少对 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-06
      • 2013-08-21
      • 2021-05-27
      • 2018-09-19
      • 1970-01-01
      • 2018-06-16
      • 2011-01-14
      相关资源
      最近更新 更多