如何使用angular8为循环项目的电子邮件和传真的每一行显示验证错误

How to show validation error for each row for email and fax for loop items using angular8

我在 bootstrap 中使用 Angular8。我已经从循环数组中输入了。如果电子邮件或传真号码有任何验证错误,则会抛出验证错误。然后,如果第一行的电子邮件字段有错误,如果第二行的传真有任何错误,它会显示。如果在第 3 行中,如果电子邮件输入错误然后更正,则第一行验证错误也会消失。

我想显示所有行的验证错误,因为传真或电子邮件字段存在错误。

HTML:

              <input type="text" class="form-control" placeholder="Email" name="Recepient"
                          formControlName="recipients" *ngIf="data.value.deliveryMethodId == 178"
                          (focusout)="validationErrorOnFocusOut('emailvalid',data)"
                          [ngClass]="{ 'is-invalid': emailsubmitted  && data.controls.recipients.errors}"
                          pattern="^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$" autocomplete="off">
              <div *ngIf="(emailsubmitted && data.controls.recipients.errors)" class="invalid-feedback">
                <div *ngIf="(emailsubmitted && data.controls.recipients.errors)">
                  Please enter valid email</div>
              </div>
              <input type='text' prefix="+1 " mask=" (000) 000-0000" class="form-control"
                          placeholder="Recepient" name="Recepient" formControlName="recipients"
                          *ngIf="data.value.deliveryMethodId == 179" maxLength="18"
                          (focusout)="validationErrorOnFocusOut('fax',data)"
                          autocomplete="off"
                          [ngClass]="{ 'is-invalid':faxsubmitted && data.controls.recipients.errors.mask}">
              <div *ngIf="faxsubmitted && data.controls.recipients.errors.mask" class="invalid-feedback">
                <div *ngIf="faxsubmitted && data.controls.recipients.errors.mask">Please enter valid fax number
                </div>
              </div>

TS:

  public validationErrorOnFocusOut(name, data) {
    if (name == "emailvalid") {
      if (data.controls.recipients.status === "VALID") {
        this.emailsubmitted = false;
      } else {
        this.emailsubmitted = true;
      }
      if (
        data.controls.recipients.value === "" ||
        data.controls.recipients.value === null
      ) {
        this.emailsubmitted = false;
      }
    } else if (name == "fax") {
      if (data.controls.recipients.status === "VALID") {
        this.faxsubmitted = false;
      } else {
        this.faxsubmitted = true;
      }
      if (
        data.controls.recipients.value === "" ||
        data.controls.recipients.value === null
      ) {
        this.faxsubmitted = false;
      }
    }
  }

DEMO

您已使用 FormBuilder 正确设置表单。我的解决方案将专注于您的表单 Reactivity

以下是我采取的步骤

  1. 删除 [disabled] 属性 上的绑定 如果您包含 [disabled] 属性
  2. ,下面是在控制台中抛出的警告

It looks like you're using the disabled attribute with a reactive form directive. If you set disabled to true
when you set up this control in your component class, the disabled attribute will actually be set in the DOM for
you. We recommend using this approach to avoid 'changed after checked' errors.

Example:
form = new FormGroup({
first: new FormControl({value: 'Nancy', disabled: true}, Validators.required),
last: new FormControl('Drew', Validators.required)
});
  1. 删除 onChange 事件处理程序。取而代之的是我们的 ngOninit 函数。我们将观察表单值的变化并对此做出反应以禁用适当的控件
      this.printListControl.valueChanges
      .pipe(
        distinctUntilChanged(),
        tap((controls: any[]) => {
          controls.forEach(({ mail, deliveryMethodId }, index) => {
            const control = this.printListControl.at(index);

            if (mail) {
              control.get("deliveryMethodId").enable({ emitEvent: false });
              control.get("recipients").enable({ emitEvent: false });
            } else {
              // I would not include below two lines for better user experience.
              control
                .get("deliveryMethodId")
                .setValue(null, { emitEvent: false });
              control.get("recipients").setValue(null, { emitEvent: false });

              control.get("deliveryMethodId").disable({ emitEvent: false });
              control.get("recipients").disable({ emitEvent: false });
            }

            // console.log(deliveryMethodId);

            control
              .get("recipients")
              .setValidators(this.getRecipientsValidation(deliveryMethodId));
          });
        })
      )
      .subscribe();
  }
  getRecipientsValidation(deliveryMethodId) {
    return +deliveryMethodId === 178
      ? [Validators.pattern(this.emailPattern), Validators.required]
      : +deliveryMethodId === 179
      ? [
          Validators.minLength(10),
            (10),
          Validators.required
        ]
      : [Validators.required];
  }

现在,只要更改 mail 值,就会启用或禁用 [​​=22=] 和 recipients 控件

我们还会根据所选的交付方式更新验证器

  1. 从 html 中删除模式验证。我们将使用 Validators.pattern

我们可以声明模式

emailPattern = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
  1. 从模板中删除 validationErrorOnFocusOut 的事件

  2. 由于我们已经删除了模板验证,我们可以使用 Validator static 类

    let printList = this.printListArray.map(x => {
      const { deliveryMethodId } = x;
      return this.fb.group({
        id: x.id,
        name: x.name,
        mail: x.mail,
        electronics: x.electronics,
        deliveryMethodId: x.deliveryMethodId,
        recipients: [
          x.recipients,
          {
            validators:
              deliveryMethodId === 178
                ? [Validators.pattern(this.emailPattern), Validators.required]
                : deliveryMethodId === 179
                ? [
                    Validators.minLength(10),
                    Validators.maxLength(10),
                    Validators.required
                  ]
                : [Validators.required],
            updateOn: "blur"
          }
        ]
      });
    });

我们正在对每个控件单独应用验证,以避免它们对其他控件的影响

  1. 最后我们的html会变成这样
<div class="custom-control custom-checkbox"
     *ngFor="let data of exampleForm.get('printList').controls; let j = index" formArrayName="printList">
  <div [formGroupName]="j">
    <table class="table table-print table-borderless">
      <tbody>
      <tr>
        <td scope="row" class="width90">{{data.value.name}}</td>

        <td class="width50">
          <input
            type="checkbox"
            name="mail"
            formControlName="mail"
          />
        </td>
        <td class="width50">
          <input
            type="checkbox"
            name="electronics"
            formControlName="electronics"
          />
        </td>
        <td class="width100">

          <select
            class="custom-select"
            formControlName="deliveryMethodId"
            name="deliveryMethodId"
            tabindex="1" (change)="dropdownSelection(j)"
          >
            <option value=null>Select One </option>
            <option
              *ngFor="let agencyType of DeliveryMethod"
              [value]="agencyType.id"
            >
              {{agencyType.label}}</option
            >
          </select>
        </td>
        <td class="width200">
          <ng-container *ngIf="data.value.deliveryMethodId == 178">
            <input type="text" class="form-control" placeholder="Email" name="Recepient"
                   formControlName="recipients" *ngIf="data.value.deliveryMethodId == 178"
                   [ngClass]="{ 'is-invalid': data.get('recipients').invalid && data.get('recipients').touched }"
                   autocomplete="off">

            <div class='invalid-feedback' *ngIf="data.get('recipients').invalid">
              Please enter valid email
            </div>
          </ng-container>
          <ng-container *ngIf="data.value.deliveryMethodId == 179">
            <input type="text"  prefix="+1 " class="form-control" placeholder="(###) ### - ####"
                   formControlName="recipients" name="recipients" autocomplete="off"
                   *ngIf="data.value.deliveryMethodId == 179"
                   mask=" (000) 000-0000" [showMaskTyped]="false"
                   [ngClass]="{ 'is-invalid' : data.get('recipients').invalid && data.get('recipients').touched }" >

            <div class='invalid-feedback'>
              Please enter valid fax number
            </div>
          </ng-container>
          <ng-container *ngIf="data.value.deliveryMethodId != '178' && data.value.deliveryMethodId != '179'">
            <input type="text" class="form-control" placeholder="Recepient" name="Recepient"
                   [ngClass]="{ 'is-invalid' : data.get('recipients').invalid && data.get('recipients').touched }"
                   formControlName="recipients"
            />
            <div class='invalid-feedback'>
              Field is required
            </div>
          </ng-container>


        </td>
      </tr>
      </tbody>
    </table>
  </div>
</div>

DEMO HERE