【问题标题】:Angular 8 - How to prevent reactive form validation when dynamic form groups has been added?Angular 8 - 添加动态表单组时如何防止反应式表单验证?
【发布时间】:2020-03-30 12:14:26
【问题描述】:

我创建了一个可重用的组件来创建/编辑我的应用程序的实体。该组件包含一个具有一些动态部分的响应式表单。

整个表单按预期工作,但我遇到了验证问题:每次单击按钮向表单添加动态表单组时,添加的表单都会显示验证错误。同样,不仅验证了动态部分,还验证了表单的其余部分。

似乎,添加动态部分,正在执行验证,就像提交按钮被按下,但它没有。

我想要实现的是能够添加动态formGroups,而无需此操作本身执行表单的验证。

我错过了什么吗?

import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {AbstractControl, FormArray, FormControl, FormGroup, Validators} from '@angular/forms';
import {Plan} from '../shared/domain/plan.model';
import {Milestone} from '../shared/domain/milestone.model';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.scss']
})
export class FormComponent implements OnInit {

  @Input() plan?: Plan;

  planForm = new FormGroup({
    id: new FormControl(
      null,
      [
        Validators.required,
        Validators.minLength(4),
        Validators.pattern('^[a-zA-Z0-9_-]+$')
      ]
    ),
    milestones: new FormArray([])
  });

  constructor() {}

  ngOnInit() {
    this.fillForm();
  }

  fillForm() {
    this.planForm.get('id').setValue(this.plan ? this.plan.getId() : '');
    this.createMilestoneFormControls();

    if (this.plan) {
      this.planForm.get('id').disable();
    }
  }

  createMilestoneFormControls() {
    if (!this.plan) {
      this.addMilestoneToFormArray();
      return;
    }

    this.plan.getMilestones().forEach((milestone: Milestone) => {
      this.addMilestoneToFormArray(milestone);
    });
  }

  addMilestoneToFormArray(milestone?: Milestone) {
    const milestonesFormArray = this.milestonesFormArray;
    milestonesFormArray.push(new FormGroup({
      description: new FormControl(milestone ? milestone.getDescription() : ''),
      startDate: new FormControl(
        milestone ? milestone.getStartDate().toISOString().substring(0, 10) : '',
        [Validators.required]
      ),
      endDate: new FormControl(
        milestone ? milestone.getEndDate().toISOString().substring(0, 10) : '',
        [Validators.required]
      ),
    }));
  }

  get milestonesFormArray() {
    return this.planForm.get('milestones') as FormArray;
  }

  removeMilestoneFromFormArray(i: number) {
    this.milestonesFormArray.removeAt(i);
  }

  getValidationMessage(field: string, fault: string): string {
    return this.validationMessages[field][fault];
  }

  getDateInputValidationMessage(fieldName: string, control: AbstractControl): string {

    if (control.errors.matDatepickerMax) {
      return this.getValidationMessage(fieldName, 'matDatepickerMax');
    }

    if (control.errors.matDatepickerParse) {
      return this.getValidationMessage(fieldName, 'matDatepickerParse');
    }

    if (!control.value && control.errors.required) {
      return this.getValidationMessage(fieldName, 'required');
    }

    return '';
  }

}
<form [formGroup]="planForm" (keydown.enter)="$event.preventDefault()">
    <mat-form-field class="formInput" appearance="outline">
    <mat-label>Relationship identifier</mat-label>
    <input matInput formControlName="id" autocomplete="off" required>
    <mat-error *ngIf="planForm.get('id').invalid">
      <div *ngIf="planForm.get('id').errors.required">{{getValidationMessage('id', 'required')}}</div>
      <div *ngIf="planForm.get('id').errors.minlength">{{getValidationMessage('id', 'minlength')}}</div>
      <div *ngIf="planForm.get('id').errors.pattern">{{getValidationMessage('id', 'pattern')}}</div>
    </mat-error>
  </mat-form-field>
  <div formArrayName="milestones">
    <div *ngFor="let milestone of milestonesFormArray.controls; let i=index"
      [formGroupName]="i.toString()"
      class="milestoneFormBlock">

      <div class="mobile">Milestone #{{i+1}}</div>
      <hr class="milestoneDivider">
      <mat-form-field class="formInputMilestone" appearance="outline" style=" margin-bottom: -1.25em">
        <mat-label>Description</mat-label>
        <input matInput formControlName="description" autocomplete="off">
      </mat-form-field>

      <mat-form-field class="formInputMilestone" appearance="outline" style=" margin-bottom: -1.25em">
        <mat-label>Start Date</mat-label>
        <input
          matInput
          [matDatepicker]="milestoneStartDate"
          formControlName="startDate"
          autocomplete="off"
          required
          placeholder="mm/dd/yyyy"
          [max]="milestone.get('endDate').value">
        <mat-datepicker-toggle matSuffix [for]="milestoneStartDate"></mat-datepicker-toggle>
        <mat-datepicker #milestoneStartDate></mat-datepicker>
        <mat-error *ngIf="milestone.get('startDate').invalid">
          <div>{{getDateInputValidationMessage('startDate', milestone.get('startDate'))}}</div>
        </mat-error>
      </mat-form-field>

      <mat-form-field class="formInputMilestone" appearance="outline" style=" margin-bottom: -1.25em">
        <mat-label>End Date</mat-label>
        <input
          matInput
          [matDatepicker]="milestoneEndDate"
          formControlName="endDate"
          autocomplete="off"
          required
          placeholder="mm/dd/yyyy"
          [min]="milestone.get('startDate').value">
        <mat-datepicker-toggle matSuffix [for]="milestoneEndDate"></mat-datepicker-toggle>
        <mat-datepicker #milestoneEndDate></mat-datepicker>
        <mat-error *ngIf="milestone.get('endDate').invalid">
          <div>{{getDateInputValidationMessage('endDate', milestone.get('endDate'))}}</div>
        </mat-error>
      </mat-form-field>

      <button class="remove-milestone-btn" mat-raised-button color="warn" (click)="removeMilestoneFromFormArray(i)">
        <fa-icon [icon]="['fas', 'trash']"></fa-icon>
      </button>

    </div>
    <button class="add-milestone-btn" mat-fab color="primary" (click)="addMilestoneToFormArray()">
      <fa-icon [icon]="['fas', 'plus']"></fa-icon>
    </button>
  </div>

  <button class="submitBtn" (click)="onSubmit()" mat-raised-button color="primary">
    <div *ngIf="plan; then thenBlock else elseBlock"></div>
    <ng-template #thenBlock>Update relationship</ng-template>
    <ng-template #elseBlock>Create relationship</ng-template>
  </button>

</form>

【问题讨论】:

    标签: angular forms validation angular-forms


    【解决方案1】:

    如果您未指定,则将按钮视为type='submit'。因此表单确实收到了submit 事件。

    当按钮点击时不打算提交时,将按钮更改为&lt;button type="button"&gt;

    【讨论】:

    • 我不敢相信...错过了我的按钮类型!非常感谢!你成功了!
    猜你喜欢
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    • 2019-05-04
    • 1970-01-01
    • 2019-07-09
    • 1970-01-01
    相关资源
    最近更新 更多