подтверждение пароля в угловом — странное поведение

#angular #angular-validation

Вопрос:

Я реализовал проверку пароля подтверждения в Angular с помощью пользовательского валидатора. Вот пользовательский класс валидатора:

 import { AbstractControl, ValidatorFn } from '@angular/forms';

export class Validation {
  static match(controlName: string, checkControlName: string): ValidatorFn {
    return (controls: AbstractControl) => {
      const control = controls.get(controlName);
      const checkControl = controls.get(checkControlName);

      if (checkControl?.errors amp;amp; !checkControl.errors.matching) {
        return null;
      }

      if (control?.value !== checkControl?.value) {
        controls?.get(checkControlName)?.setErrors({ matching: true });
        return { matching: true };
      } else {
        return null;
      }
    };
  }
}
 

Я использую реактивную форму, вот как я ее создаю:

 initSignupForm() {
    this.signupForm = new FormGroup(
      {
        email: new FormControl(this.formData.email, [
          Validators.required,
          Validators.email,
        ]),
        password: new FormControl(this.formData.password, [
          Validators.required,
        ]),
        passwordConfirm: new FormControl(this.formData.passwordConfirm, [
          Validators.required,
        ]),
      },
      { validators: [Validation.match('password', 'passwordConfirm')] }
    );
  }
 

И это компонент html:

 <div class="card">
  <kendo-card width="320px">
    <h2>Regisztráció</h2>
    <form [formGroup]="signupForm">
      <kendo-formfield>
        <kendo-textbox placeholder="E-mail cím" formControlName="email">
          <ng-template kendoTextBoxPrefixTemplate>
            <kendo-svg-icon [icon]="icons.user"></kendo-svg-icon>
            <div id="empty-div"></div>
          </ng-template>
        </kendo-textbox>
        <kendo-formerror *ngIf="signupForm.controls.email.errors?.required"
          >Kötelező mező</kendo-formerror
        >
        <kendo-formerror *ngIf="signupForm.controls.email.errors?.email"
          >Hibás e-mail formátum</kendo-formerror
        >
      </kendo-formfield>
      <kendo-formfield>
        <kendo-textbox
          placeholder="Jelszó"
          #tbxPassword
          formControlName="password"
        >
          <ng-template kendoTextBoxPrefixTemplate>
            <button
              id="tbxPassword"
              kendoButton
              icon="eye"
              (click)="togglePass()"
            ></button>
          </ng-template>
        </kendo-textbox>
        <kendo-formerror>Kötelező mező</kendo-formerror>
      </kendo-formfield>
      <kendo-formfield>
        <kendo-textbox
          placeholder="Jelszó még egyszer"
          #tbxRepeatPassword
          formControlName="passwordConfirm"
        >
          <ng-template kendoTextBoxPrefixTemplate>
            <button kendoButton icon="eye" (click)="togglePassRep()"></button>
          </ng-template>
        </kendo-textbox>
        <kendo-formerror
          *ngIf="signupForm.controls.passwordConfirm.errors?.required"
          >Kötelező mező</kendo-formerror
        >
        <kendo-formerror *ngIf="signupForm.errors?.matching"
          >A két jelszó nem egyezik</kendo-formerror
        >
      </kendo-formfield>
      <button class="btn" kendoButton [primary]="true" (click)="submitForm()">
        ÚJ FIÓK LÉTREHOZÁSA
      </button>
      <div class="link">
        <span>Már van fiókod? </span>
        <a href="#" (click)="backToLogin()">Jelentkezz be</a>
      </div>
    </form>
  </kendo-card>
  <lang-selector></lang-selector>
</div>
 

Это работает, но со следующим побочным эффектом. Например, если я введу » a «в поле пароля, а затем» b » в поле подтверждения пароля, я получу сообщение об ошибке. Хорошо. Теперь, если я изменю » b » на «a», сообщение об ошибке исчезнет, форма может быть отправлена. Хорошо. Но если я изменю первый пароль («a») на «b», сообщение об ошибке тоже исчезнет, но поле подтверждения пароля останется красным, и я не смогу отправить форму. В самой форме больше нет ошибок (я проверил это в консоли), но в самом поле все еще есть эта matching ошибка. Почему это происходит?

Комментарии:

1. Решена ли ваша проблема?

Ответ №1:

Проблема в том, что здесь Validation.match

 controls?.get(checkControlName)?.setErrors({ matching: true });
 

Вы вручную устанавливаете проверку checkControlName , но она должна быть включена в FormGroup. Из-за чего каким-то образом проверка смешивается и что приводит к неожиданной проверке. Я попытался разгадать сценарий, но не смог его найти.

Чтобы решить вашу проблему.

Удалите controls?.get(checkControlName)?.setErrors({ matching: true }); то, что находится внутри if (control?.value !== checkControl?.value)

Добавьте ниже getter в component.ts: — Чтобы получить FormGroup, чтобы мы могли использовать его в нашем шаблоне для проверки.

 get fg(): FormGroup {
    return this.signupForm as FormGroup;
}
 

Изменить

 <kendo-formerror *ngIf="signupForm.errors?.matching">
    A két jelszó nem egyezik
</kendo-formerror>
 

Для

 <kendo-formerror *ngIf="fg.hasError('matching')">
    A két jelszó nem egyezik
</kendo-formerror>
 

Вот и все : Аналогичная демонстрация

Комментарии:

1. У меня тоже была подобная мысль, и я прокомментировал это controls?.get(checkControlName)?.setErrors({ matching: true }); , когда пытался отследить проблему. Но безуспешно. Оказалось, что мне пришлось убрать kendo-formerror тег из kendo-formfield тега, и теперь даже с этим кодом signupForm.errors?.matching я получаю правильное поведение. Спасибо за вашу помощь, а также спасибо @TotallyNewb.

2. Это смутило меня, когда я использовал matching имя, Так как ошибка была такой, как { matching: true } я думаю { notMatching : true } , будет более точной.

3. Да, вы правы. Я уже исправил это.

Ответ №2:

Это связано с тем, что вы вручную устанавливаете ошибки в passwordConfirm элементе управления, но вы проверяете наличие ошибок в самой форме, чтобы отобразить сообщение об ошибке. Поскольку значение passwordConfirm не было изменено, список ошибок не был очищен.

Это означает, что ошибка не будет отображаться (так как вы возвращаете значение null из своего валидатора), но форма недействительна (так как в ней все еще есть ошибка passwordConfirm ).

Таким образом, вам нужно либо удалить строку, которая задает ошибки в самом элементе управления ( controls?.get(checkControlName)?.setErrors({ matching: true }); ), либо убедиться, что при каждой оценке вашего валидатора вы либо добавляете, либо удаляете ошибку в массив существующих ошибок.