首页 > 解决方案 > 将 FormArray 与来自响应和 mat-checkbox 的对象一起使用

问题描述

完全消化了 Angular Reactive forms 文档后,我仍在努力实现以下功能:

使用我的 NgRx 商店中的分区列表,在 Angular 反应形式中为每个分区名称输出一个 mat-checkbox 并检查状态(使用 division.current 属性 - 以便默认检查当前活动的分区)。

这是我所在的位置:

新赛季组件.ts

export class NewSeasonComponent implements OnInit {
  chooseDivisions: FormGroup;
  divisions: FormArray;
  allDivisions: Division[];
  constructor(
      private fb: FormBuilder,
      private store: Store<AppState>
  ) {
    }
  ngOnInit() {
    this.store.dispatch(new AllDivisionsRequested());
    this.store
        .pipe(
            select(selectAllDivisions)
        ).subscribe(divisions => this.allDivisions = divisions);

    this.chooseDivisions = this.fb.group({
      divisions: this.fb.array([])
    });

    this.addDivisions();

  }
  createDivisionFormControl(division: Division): FormGroup {
    return this.fb.group({
      id: division.id,
      name: division.name,
      current: division.current
    });
  }
  addDivisions(): void {
    this.divisions = this.chooseDivisions.get('divisions') as FormArray;
    this.allDivisions.map(
        division => {
          this.createDivisionFormControl(division);
        }
    );
  }

总之 - 从商店中获取部门,创建一个包含空 formArray 的 formGroup。然后运行一个方法来映射分区并调用另一个方法将它们创建为 formGroups。

** new-season-component.html**

<form [formGroup]="chooseDivisions">
  <ng-template matStepLabel>Choose which teams are part of this season</ng-template>
  <div formArrayName="divisions">
    <div *ngFor="let division of chooseDivisions.get('divisions').controls; let i = index;">
      <div [formGroupName]="i">
        <mat-checkbox formControlName="division">{{ division[i].name }}</mat-checkbox>
      </div>
    </div>
  </div>
  <div>
    <button mat-button matStepperNext>Next</button>
  </div>
</form>

我已经使用了各种在线材料来达到这一点 - 包括这篇文章,但似乎没有一个是我正在寻找的 - 即在加载时添加一个部门列表作为复选框,而不是单击按钮添加的功能一个新的空白表单控件。

我显然在做一些根本错误的事情。我什至应该在这里使用反应形式吗?

标签: angulartypescriptangular-reactive-forms

解决方案


表单数组必须始终是表单组的子级,否则会抛出错误。因此,您必须在 ngOnInit 中以表单数组作为控件来启动一个表单组。

this.divisionsFormGroup = this.fb.group({
    divisions: this.fb.array([])
});

我建议之后推入表单数组:

this.allDivisions.map(divisionFromStore => this.divisionsFormGroup.controls.divisions.push(createDivisionFormControl(divisionFromStore));

然后你的HTML:

<form [formGroup]="divisionsFormGroup">
  <ng-template matStepLabel>Choose which teams are part of this season</ng-template>
  <div formArrayName="divisions">
    <div *ngFor="let division of divisions.controls; let i = index;"> // I can't quite recall if you can call controls off of the formArrayName, or if you have to use divisionsFormGroup.controls.divisions.controls
      <div [formControlName]="i">
        <mat-checkbox>{{ division.controls.name.value }}</mat-checkbox> // Try just division.name if that doesn't work
      </div>
    </div>
  </div>
  <div>
    <button mat-button matStepperNext>Next</button>
  </div>
</form>

打字的问题...

  • 转换表单组创建方法的返回值

return this.fb.group({etc}) as AbstractControl // I can't quite recall if it'll error out and say there's no overlap between properties. If that doesn't work, do the below...

  • 请改用表单数组setValue()

const arrayOfAllDivisionsFormGroups = this.allDivisions.map(divisionFromStore => createDivisionFormControl(divisionFromStore));

this.divisionsFormGroup.controls.divisions.setValue(arrayOfAllDivisionsFormGroups);

不应该有类型冲突 b/csetValue()需要any[]


推荐阅读