You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在mat-stepper中验证FormGroup的数组是否为空

解决Mat-Stepper中FormArray验证不生效的问题

问题核心

你当前的验证不生效,是因为FormArray skillsOffer 和业务数据 job.skillsOffer 完全脱节:验证规则只作用于FormArray,但你操作的是job.skillsOffer,FormArray始终是空数组,导致验证逻辑完全没触发。同时HTML中的表单结构也存在错误,比如formArrayName放置位置不对,错误地给FormArray绑定了formControlName。

修复步骤

1. 新增FormArray的Getter(方便访问)

在组件类中添加一个getter,快速获取skillsOffer这个FormArray:

export class CreateYourJobComponent implements OnInit {
  public job = new Job();
  // ... 其他表单组定义

  // 新增getter
  get skillsOfferFormArray(): FormArray {
    return this.secondFormGroup.get('skillsOffer') as FormArray;
  }

  constructor(private _formBuilder: FormBuilder, public dialog: MatDialog) { }

  // ... 其他方法
}

2. 同步FormArray与业务数据

修改addSkillsOffer和removeSkills方法,确保每次操作job.skillsOffer时,同步更新FormArray的内容:

修改addSkillsOffer方法:

addSkillsOffer(data: EditOffer) {
  this.dialog.open(OfferDialogComponent, { data })
    .afterClosed().subscribe((res) => {
      if (!res) return;

      // 更新业务数据
      this.job.skillsOffer = res.skillsOffer;
      // 清空并同步FormArray
      this.skillsOfferFormArray.clear();
      res.skillsOffer.forEach(skill => {
        // 仅用于触发验证,无需绑定具体字段,用空FormGroup即可
        this.skillsOfferFormArray.push(this._formBuilder.group({}));
      });
    });
}

修改removeSkills方法:

removeSkills(index: number) {
  // 删除业务数据中的项
  this.job.skillsOffer.splice(index, 1);
  // 同步删除FormArray中的项
  this.skillsOfferFormArray.removeAt(index);
}

3. 修复HTML表单结构

移除错误的隐藏input,修正formArrayName的位置,并添加验证错误提示:

<mat-horizontal-stepper [linear]="true" #stepper style="margin-left: 20px; margin-top: 1rem">
  <!-- 第一个步骤省略 -->
  <mat-step [stepControl]="secondFormGroup">
    <form [formGroup]="secondFormGroup">
      <li class="mat-form-field--inline">
        <mat-form-field appearance="fill">
          <mat-label> {{ "skills.offer" | translate }} </mat-label>
          <div class="card__body d-flex column">
            <!-- 将formArrayName移到*ngFor的父容器上 -->
            <div class="d-flex align-items-center card__body__list" formArrayName="skillsOffer">
              <div *ngFor="let sp of job.skillsOffer; let i = index" class="d-flex justify-content-between pr-1">
                <div class="card__text">
                  {{ sp.name }}
                  <span class="fa fa-remove" (click)="removeSkills(i)"></span>
                </div>
              </div>
              <button class="btn btn-light ml-1" (click)="addSkillsOffer({createJob: true})">
                <i class="fa fa-pencil"></i>
              </button>
            </div>
          </div>
          <!-- 显示验证错误提示 -->
          <mat-error *ngIf="skillsOfferFormArray.invalid">
            请至少添加一项技能
          </mat-error>
        </mat-form-field>
      </li>
    </form>
  </mat-step>
</mat-horizontal-stepper>

4. 可选:自定义数组非空验证器

如果Validators.required对你的场景不够明确,可以自定义一个验证器,确保数组长度大于0:

// 自定义验证器函数
export function nonEmptyArrayValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const formArray = control as FormArray;
    return formArray.length === 0 ? { emptyArray: true } : null;
  };
}

// 在定义secondFormGroup时使用
secondFormGroup = this._formBuilder.group({
  pcKnowledge:[''],
  skillsOffer: this._formBuilder.array([], nonEmptyArrayValidator()),
  driveLicense:  [''],
  language: [''],
  qualifications:  [''],
});

然后在HTML中修改错误提示的判断:

<mat-error *ngIf="skillsOfferFormArray.hasError('emptyArray')">
  请至少添加一项技能
</mat-error>

修复逻辑说明

  • FormArray的验证状态完全由自身内容决定,必须让它和业务数据同步,才能触发正确的验证逻辑
  • 修正formArrayName的位置,确保表单控件与FormArray正确关联
  • 移除错误的formControlName绑定,因为skillsOffer是FormArray而非单个FormControl

内容的提问来源于stack exchange,提问作者TheCoderGuy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 18:16:02