【问题标题】:Angular - Dynamic FormArray controls not validatedAngular - 未验证动态 FormArray 控件
【发布时间】:2021-09-13 23:26:16
【问题描述】:

在我的 Angular-12 项目中,我有这个使用 Reactive Form 的 Dynamic FormArray。

组件:

updateContact() {
  this.contactInfoForm = this.fb.group({
    id: [''],
    current_residential_address: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(500)]],
    contacts: this.fb.array([
      this.addContactFormGroup()
    ])
  });
}

addContactFormGroup(): FormGroup {
  return this.fb.group({
    phone_type_id: ['', Validators.required],
    phone_number: ['', [Validators.required, Validators.maxLength(15)]],
    is_primary_contact_number: ['']
  });
}

addContactButtonClick(): void {
  ( < FormArray > this.contactInfoForm.get('contacts')).push(this.addContactFormGroup());
}

get fc() {
  return this.contactInfoForm.controls;
};

contactValidate() {
  if (!this.contactInfoForm.valid) {
    this.contactInfoForm.markAllAsTouched();
    return;
  }
}

ngOnInit(): void {
  this.updateContact();
  this.loadAllParameters();
}

loadAllParameters() {
  this.employeeService.getEmployeeParameters().subscribe(
    data => {
      this.phonetypes = data.results.phonetypes;
    }
  );
}

HTML:

<form [formGroup]="contactInfoForm">
  <div class="row">
    <div class="col-12 col-md-12">
      <div class="form-group">
        <label for="current_residential_address">Current Residential Address:<span style="color:red;">*</span></label>
        <textarea rows="2" formControlName="current_residential_address" name="description" type="text" placeholder="22, Alexander Close ..." class="form-control mb-3" required>
                              </textarea>
      </div>
      <div *ngIf="fc.current_residential_address.touched && fc.current_residential_address.invalid">
        <div *ngIf="fc.current_residential_address.hasError('required')">
          <div class="text-danger">
            Current Residential Address is required!
          </div>
        </div>
        <div *ngIf="fc.current_residential_address.hasError('minlength')">
          <div class="text-danger">
            Current Residential Address cannot be less than 2 characters!
          </div>
        </div>
        <div *ngIf="fc.current_residential_address.hasError('maxlength')">
          <div class="text-danger">
            Current Residential Address cannot be more than 500 characters!
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="row">
    <div formArrayName="contacts" class="col-md-12" *ngFor="let contact of contactInfoForm.get('contacts').controls">
      <div formGroupName="0" class="row">
        <div class="col-12 col-md-4">
          <div class="form-group">
            <label for="phone_number">Phone Number:<span style="color:red;">*</span></label>
            <div class="input-group mb-4">
              <ngx-intl-tel-input [cssClass]="'form-control mb-4'" [preferredCountries]="preferredCountries" [enableAutoCountrySelect]="false" [enablePlaceholder]="true" [searchCountryFlag]="true" [searchCountryField]="[SearchCountryField.Iso2, SearchCountryField.Name]"
                [selectFirstCountry]="false" [selectedCountryISO]="CountryISO.Nigeria" [phoneValidation]="true" [separateDialCode]="true" name="phone_number" formControlName="phone_number">
              </ngx-intl-tel-input>
            </div>
          </div>
          <div *ngIf="fc.phone_number.touched && fc.phone_number.invalid">
            <div *ngIf="fc.phone_number.hasError('required')">
              <div class="text-danger">
                Phone Number is required!
              </div>
            </div>
            <div *ngIf="fc.phone_number.hasError('validatePhoneNumber')">
              <div class="text-danger">
                Invalid Phone Number!
              </div>
            </div>
          </div>
        </div>
        <div class="col-12 col-md-4">
          <div class="form-group">
            <label for="phone_type_id">Phone Type:<span style="color:red;">*</span></label>
            <ng-select [items]="phonetypes" [selectOnTab]="true" [searchable]="true" bindValue="id" bindLabel="type_name" placeholder="Select Phone Type" [multiple]="false" [clearable]="true" required formControlName="phone_type_id">
            </ng-select>
          </div>
          <div *ngIf="fc.phone_type_id.touched && fc.phone_type_id.invalid">
            <div *ngIf="fc.phone_type_id.hasError('required')">
              <div class="text-danger">
                Phone Type is required!
              </div>
            </div>
          </div>
        </div>
        <div class="col-12 col-md-2">
          <div class="form-group">
            <label for="phone_type_id">Is Primary Line?:</label><br>
            <input type="checkbox" class="form-check-input" id="exampleCheck2">
          </div>
        </div>
        <div class="col-12 col-md-2">
          <div class="form-group">
            <button type="button" class="btn btn-danger float-right"><i class="fas fa-minus"></i> Remove</button>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div class="card-footer">
    <button type="button" class="btn btn-primary float-right" (click)="addContactButtonClick()"><i class="fas fa-plus"></i> Add item</button>
    <button type="submit" class="btn btn-success" [disabled]="isLoading" class="btn btn-success" (click)="contactValidate()">
                      <span *ngIf="isLoading" class="spinner-border spinner-border-sm mr-1"></span>
                      <i class="fa fa-save" aria-hidden="true"></i> Save</button>
  </div>
</form>

仅验证了不属于表单数组的 current_residential_address。

但未验证 FormArray (phone_type_id, phone_number) 控件。

我该如何解决这个问题?

谢谢

【问题讨论】:

  • 你得到Phone Number is required!...不,你不会得到。在addContactFormGroup 下没有验证将起作用
  • @NavnathJadhav - 不,我没听懂。我该怎么办?
  • 我正在发布完整的答案
  • @NavnathJadhav - 我根本没有对 formArray 进行任何验证。
  • 我很惊讶您没有收到任何错误。我在stackblitz.com 中添加了您的代码后,我收到了关于验证的错误

标签: angular


【解决方案1】:

因为contactsformGroup 的数组。让我们从更改以下行开始

<div formArrayName="contacts" class="col-md-12" *ngFor="let contact of contactInfoForm.get('contacts').controls">
      <div formGroupName="0" class="row">
      ...
      </div>
</div>

<div formArrayName="contacts" class="col-md-12" *ngFor="let contact of contacts.controls; let i = index">
      <div [formGroupName]="i" class="row">
       ...
       </div>
 </div>

在 TS 文件中添加 getter 以获取联系人:

get contacts() {
    return this.contactInfoForm.controls['contacts'] as FormArray;
}

看看你的fc getter。它返回的contactInfoForm 控件,包括current_residential_addresscontact FormArray。

get fc() {
    return this.contactInfoForm.controls;
  }

您的验证码。它在fc 中找到phone_number,当然它不会找到。我们需要告诉他在contactFormArray 中找到它并提供formGroup 索引

fc.phone_number.touched && fc.phone_number.invalid

FormGroup 索引在let i = index 中可用, 现在,我们需要一个接收索引并从contact FormArray 返回FormGroup 的方法。

getFormGroup(index: number): FormGroup {
  return this.contacts.at(index) as FormGroup;
}

现在访问验证对象:

<div *ngIf="getFormGroup(i).get('phone_number').hasError('required')">
 ....
</div>

<div *ngIf="getFormGroup(i).get('phone_type_id').hasError('required')">
 .....
</div>

在演示中,我添加了检查有效/无效表单

{{ "Is Form Valid : "+contactInfoForm.valid}}

Demo

如果有什么遗漏请告诉我。

【讨论】:

  • 感谢您的努力。一切都很好,除了它强调了 hasError('required') 并触摸并显示了这个错误:对象可能是'null'。我该如何摆脱它?
  • @user11352561 尝试将! 非空断言运算符用作getFormGroup(i).get('phone_number')!.hasError('required')
【解决方案2】:

您没有将 DOM 内容动态分配给您迭代的 FormArray 的特定索引。

<div formArrayName="contacts" class="col-md-12" *ngFor="let contact of contactInfoForm.get('contacts').controls; let i = index;">
      <div [formGroupName]="i" class="row">
        <div class="col-12 col-md-4">
          ...
        </div>
      </div>
    </div>

所以不是&lt;div formGroupName="0" class="row"&gt; 而是动态设置它以使用正确的索引。

【讨论】:

    猜你喜欢
    • 2019-11-23
    • 2020-06-25
    • 1970-01-01
    • 1970-01-01
    • 2020-11-15
    • 2018-09-11
    • 2018-07-20
    • 2019-02-06
    • 2018-11-21
    相关资源
    最近更新 更多