【问题标题】:Angular 11 - Validating a child form generated in a for loopAngular 11 - 验证在 for 循环中生成的子表单
【发布时间】:2021-07-24 07:25:00
【问题描述】:

我正在使用 Angular Reactive 表单。我的父组件有一个表单,Add FormSubmitReset 按钮。当我点击Add form 时,它会向DOM 添加一个名为profile-form 的子表单。 profile-form 有两个字段 First NameEmail。这个想法是多次重用profile-form 组件,单击添加按钮。每个表单都需要验证,父表单应该知道每个子表单的验证状态。

我的父表单有这个 HTML 以在 for 循环中生成子表单。

<div *ngFor="let fg of formList.controls; let infoIndex = index">
    <app-profile-form formControlName="fg" [formList]="formList" 
                      [formIndex]="infoIndex"></app-profile-form>
  </div>

当我查看控制台时,我似乎收到了一个错误,即在formList.controls 中找不到formControlName 'fg'。如何修复我的父表单和子表单之间的 formControls 映射,以便验证有效?

Stackblitz here

【问题讨论】:

    标签: angular typescript angular-reactive-forms controlvalueaccessor


    【解决方案1】:

    让我们尝试分析表单。

    您期望下面作为表单的最终值

    {
      "formList": [  
        {
          "firstName": "",
          "email": ""
        },
        {
          "firstName": "",
          "email": ""
        },
        {
          "firstName": "",
          "email": ""
        }
      ]
    }
    

    在上面我们有

    form  => FormGroup : form 
      formList => FormArray : formList 
        1 => FormControl with value {email: '', firstName} : 1
        2 => FormControl with value {email: '', firstName} : 2
        3 => FormControl with value {email: '', firstName} : 3
    

    所以在表单中我们必须有这个结构才能让表单工作

    <form [formGroup]="signupForm" (ngSubmit)="submit()">
      <ng-container formArrayName='formList'>
        <div *ngFor="let fg of formList.controls; let infoIndex = index">
          <app-profile-form [formControlName]="infoIndex" [formIndex]="infoIndex"></app-profile-form>
        </div>
      </ng-container>
    
      <button>Sign Up</button>
      <button type="button" (click)="resetForm()">Reset</button>
    </form>
    
    

    其他一些修改将包括

    更改formListGroupDef

        return this.formBuilder.control(
          {
            firstName: "",
            email: ""
          },
          Validators.required
        );
    

    注册表格

        this.signupForm = this.formBuilder.group({
          formList: this.formBuilder.array([
            this.formListGroupDef()
          ])
        });
    

    我还对你的ProfileFormComponent做了一些改动

    export class ProfileFormComponent implements ControlValueAccessor, OnDestroy {
      @Input() formIndex: any;
      destroyed$ = new Subject<any>();
      form: FormGroup;
      get firstNameControl() {
        return this.form.controls.firstName;
      }
    
      get emailControl() {
        return this.form.controls.email;
      }
    
      constructor(private formBuilder: FormBuilder) {
        this.form = this.formBuilder.group({
          firstName: ["", Validators.required],
          email: ["", Validators.required]
        });
    
        this.form.valueChanges.pipe(
          filter(({firstName, email}) => firstName.length > 0 || email.length > 0 ),
          takeUntil(this.destroyed$)
        ).subscribe(value => {
          this.onChange(value);
          this.onTouched();
        });
      }
    
      ngOnDestroy() {
        this.destroyed$.next();
      }
    
      onChange: any = () => {};
      onTouched: any = () => {};
    
      registerOnChange(fn) {
        this.onChange = fn;
      }
    
      writeValue(value) {
        if (value) {
          this.form.patchValue(value);
        }
      }
    
      registerOnTouched(fn) {
        this.onTouched = fn;
      }
    
      validate(_: FormControl) {
        return this.form.valid ? null : { profile: { valid: false } };
      }
    

    See Demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-14
      • 2018-06-15
      • 2023-01-19
      • 1970-01-01
      • 1970-01-01
      • 2020-05-19
      相关资源
      最近更新 更多