Angular 8 - Как предотвратить реактивную проверку формы при добавлении динамических c групп форм? - PullRequest
0 голосов
/ 30 марта 2020

Я создал повторно используемый компонент для создания / редактирования объекта моего приложения. Этот компонент содержит реактивную форму, которая имеет несколько динамических c частей.

Вся форма работает, как и ожидалось, но я столкнулся с проблемой с проверкой: каждый раз, когда я нажимаю кнопку, чтобы добавить динамическую c форму группа к форме, форма добавлена ​​с указанием ошибок проверки. Кроме того, проверяется не только часть Dynami c, но и остальная часть формы.

Похоже, что при добавлении части Dynami c выполняется проверка, как если бы кнопка отправки была нажата, но это не так.

Чего я хочу добиться - это иметь возможность добавлять динамические c 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>

1 Ответ

1 голос
/ 30 марта 2020

Кнопка считается type='submit', если вы не укажете это. Поэтому форма действительно получает событие submit.

Измените кнопки на <button type="button">, если отправка не предназначена для нажатия кнопки.

...