Код прыгает прямо в валидатор и все ломает

Я написал свои собственные валидаторы для проверки полей ввода моей реактивной формы, но они, похоже, не работают. Первые два никогда не вызывают ошибки, а последний ломает все, как только я добавляю его в свой код. С помощью augury я отлаживал все, что мог, и обнаружил, что с моим validatePasswords он сразу же переходит к методу, в то время как я даже ничего не трогал. Если кто-нибудь из вас сможет понять, почему это происходит или почему другие мои валидаторы никогда не выдают ошибку, это было бы потрясающе!

Мои 3 пользовательских валидатора

function validateEmail(control: FormGroup): { [key: string]: any } {
  var mailReg = /^([a-zA-Z]+[a-zA-Z0-9.\-_éèàùäëïöüâêîôû]*)@([a-z]+)[.]([a-z]+)([.][a-z]+)*$/g;
  if (!mailReg.test(control.get('email').value)) {
    return { noValidEmail: true };
  }
  return null;
}
function validatePhone(control: FormGroup): { [key: string]: any } {
  var phoneReg = /^0{0,2}(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)\d{7,14}$/;
  if (!phoneReg.test(control.get('phone').value)) {
    return { noValidPhone: true };
  }
  return null;
}

function validatePassword(control: FormGroup): { [key: string]: any } {
  if (
    control.get('password').value !== control.get('passwordConfirmation').value
  ) {
    return { noMatchingPasswords: true };
  }
  return null;
}

мой конструктор и форма:

 public register: FormGroup;
  constructor(
    public dialogRef: MatDialogRef<RegisterFormComponent>,
    private fb: FormBuilder,
    private http: HttpClient
  ) {}

  ngOnInit() {
    this.register = this.fb.group({
      firstName: ['', [Validators.required, Validators.minLength(2)]],
      lastName: ['', [Validators.required, Validators.minLength(2)]],
      email: [
        '',
        [Validators.required, Validators.minLength(5)],
        validateEmail
      ],
      phone: [
        '',
        [Validators.required, Validators.minLength(8)],
        validatePhone
      ],
      country: [''],
      password: ['', [Validators.required, Validators.minLength(5)]],
      passwordConfirmation: [
        '',
        [Validators.required, Validators.minLength(5), validatePassword]
      ]
    });
  }

мой метод сообщения об ошибке

  getErrorMessage(errors: any) {
    if (errors.required) {
      return 'is required';
    } else if (errors.noValidEmail) {
      return 'not a valid email';
    } else if (errors.noValidPhone) {
      return 'no valid phone number';
    } else if (errors.noMatchingPasswords) {
      return 'passwords don\'t match';
    } else if (errors.minlength) {
      return `need at least ${errors.minlength.requiredLength} characters`;
    }
  }

ошибка, которую он производит:

ERROR TypeError: Cannot read property 'get' of undefined
    at FormGroupDirective.push../node_modules/@angular/forms/fesm5/forms.js.FormGroupDirective.addControl (forms.js:5280)
    at FormControlName.push../node_modules/@angular/forms/fesm5/forms.js.FormControlName._setUpControl (forms.js:5882)
    at FormControlName.push../node_modules/@angular/forms/fesm5/forms.js.FormControlName.ngOnChanges (forms.js:5803)
    at checkAndUpdateDirectiveInline (core.js:22085)
    at checkAndUpdateNodeInline (core.js:23353)
    at checkAndUpdateNode (core.js:23315)
    at debugCheckAndUpdateNode (core.js:23949)
    at debugCheckDirectivesFn (core.js:23909)
    at Object.eval [as updateDirectives] (RegisterFormComponent.html:5)
    at Object.debugUpdateDirectives [as updateDirectives] (core.js:23901)

наконец, моя форма в html

<h3 mat-dialog-title>Register</h3>
<mat-dialog-content>
  <form [formGroup] = "register" (ngSubmit) = "onSubmit()">
    <mat-form-field>
      <input matInput aria-label = "First name" placeholder = "First name" type = "text" formControlName = "firstName"
        class = "browser-default" required />
      <mat-error *ngIf = "register.get('firstName')['errors'] && register.get('firstName').touched">
        {{ getErrorMessage(register.get('firstName')['errors']) }}
      </mat-error>
    </mat-form-field>
    <mat-form-field>
      <input matInput aria-label = "Last name" placeholder = "Last name" type = "text" formControlName = "lastName"
        class = "browser-default" required />
      <mat-error *ngIf = "register.get('lastName')['errors'] && register.get('lastName').touched">
        {{ getErrorMessage(register.get('lastName')['errors']) }}
      </mat-error>
    </mat-form-field>
    <mat-form-field>
      <input matInput aria-label = "Email" placeholder = "Email" type = "text" formControlName = "email" class = "browser-default"
        required />
      <mat-error *ngIf = "register.get('email')['errors'] && register.get('email').touched">
        {{ getErrorMessage(register.get('email')['errors']) }}
      </mat-error>
    </mat-form-field>
    <mat-form-field>
      <input matInput aria-label = "Phone" placeholder = "Phone" type = "text" formControlName = "phone" class = "browser-default"
        required />
      <mat-error *ngIf = "register.get('phone')['errors'] && register.get('phone').touched">
        {{ getErrorMessage(register.get('phone')['errors']) }}
      </mat-error>
    </mat-form-field>
    <mat-form-field>
      <input matInput aria-label = "Country" placeholder = "Country" type = "text" formControlName = "country"
        class = "browser-default" />
    </mat-form-field>
    <mat-form-field>
      <input matInput aria-label = "Password" placeholder = "Password" type = "password" formControlName = "password"
        class = "browser-default" required />
      <mat-error *ngIf = "register.get('password')['errors'] && register.get('password').touched">
        {{ getErrorMessage(register.get('password')['errors']) }}
      </mat-error>
    </mat-form-field>
    <mat-form-field>
      <input matInput aria-label = "Confirmation Password" placeholder = "Confirmation Password" type = "password"
        formControlName = "passwordConfirmation" class = "browser-default" required />
      <mat-error *ngIf = "register.get('passwordConfirmation')['errors'] && register.get('passwordConfirmation').touched">
        {{ getErrorMessage(register.get('passwordConfirmation')['errors']) }}
      </mat-error>
    </mat-form-field>
    <div class = "buttonDiv">
      <button mat-button (click) = "onNoClick()">Cancel</button>
      <button mat-button type = "submit" [disabled] = "!register.valid">Register</button>
    </div>
  </form>
</mat-dialog-content>

Обновлять:

эти ошибки новые, но теперь они также появляются:

ERROR Error: formGroup expects a FormGroup instance. Please pass one in.

       Example:


    <div [formGroup] = "myGroup">
      <input formControlName = "firstName">
    </div>

    In your class:

    this.myGroup = new FormGroup({
       firstName: new FormControl()
    });
    at Function.push../node_modules/@angular/forms/fesm5/forms.js.ReactiveErrors.missingFormException (forms.js:1443)
    at FormGroupDirective.push../node_modules/@angular/forms/fesm5/forms.js.FormGroupDirective._checkFormPresent (forms.js:5414)
    at FormGroupDirective.push../node_modules/@angular/forms/fesm5/forms.js.FormGroupDirective.ngOnChanges (forms.js:5237)
    at checkAndUpdateDirectiveInline (core.js:22085)
    at checkAndUpdateNodeInline (core.js:23353)
    at checkAndUpdateNode (core.js:23315)
    at debugCheckAndUpdateNode (core.js:23949)
    at debugCheckDirectivesFn (core.js:23909)
    at Object.eval [as updateDirectives] (RegisterFormComponent.html:3)
    at Object.debugUpdateDirectives [as updateDirectives] (core.js:23901)

а также

ERROR TypeError: Cannot read property 'value' of null
    at validatePassword (register-form.component.ts:29)
    at forms.js:658
    at Array.map (<anonymous>)
    at _executeValidators (forms.js:658)
    at FormControl.validator (forms.js:623)
    at FormControl.push../node_modules/@angular/forms/fesm5/forms.js.AbstractControl._runValidator (forms.js:2914)
    at FormControl.push../node_modules/@angular/forms/fesm5/forms.js.AbstractControl.updateValueAndValidity (forms.js:2890)
    at new FormControl (forms.js:3241)
    at FormBuilder.push../node_modules/@angular/forms/fesm5/forms.js.FormBuilder.control (forms.js:6462)
    at FormBuilder.push../node_modules/@angular/forms/fesm5/forms.js.FormBuilder._createControl (forms.js:6502)

(строка 29 это: control.get('password').value !== control.get('passwordConfirmation').value)

Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
1
0
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Учитывая, что пользовательский валидатор validatePassword включает перекрестная проверка (проверка нескольких полей — FormControls password и passwordConfirmation), вы должны передать этот валидатор во втором аргументе инициализации формы register.

Вы можете оставить другие FormControls такими, какие они есть. Удалите validatePassword из passwordConfirmation и добавьте его во второй аргумент formBuilder.

this.register = this.fb.group({
  .
  .
  password: ['', [Validators.required, Validators.minLength(5)]],
  passwordConfirmation: [
    '',
    [Validators.required, Validators.minLength(5)]
  ]
}, { validators: validatePassword });

Что касается вашей второй проблемы, это связано с тем, что register FormGroup не определена при отображении страницы. Вы должны переместить его в свой конструктор или просто инициализировать FormControls, когда вы объявляете свойство «register» в своем классе.

constructor(
    public dialogRef: MatDialogRef<RegisterFormComponent>,
    private fb: FormBuilder,
    private http: HttpClient
  ) {
    this.register = fb.group({ 
      .
      .
      // your FormControls
      .
    });
  }

Или

export class YourComponent implements OnInit {

  public register: FormGroup = this.fb.group({ 
   .
   .
   // your FormControls
   .
  })

Итак, я сделал то, что вы сказали, но это не сработало, поэтому я немного импровизировал и поместил каждый валидатор в { validators : [validatePassword, validatePhone, validateEmail ]} Валидации работают, но сообщения все равно не отображаются. Почему?

Mout Pessemier 09.04.2019 18:35

Ах, рад слышать, что эта часть работает. Хм.. Нет сообщения об ошибке, да? Вы, должно быть, имеете в виду getErrorMessage()? Вероятно, это связано с тем, что вам может потребоваться передать свойство error из register FormGroup вместо свойства ошибки из каждого отдельного элемента управления FormControl. Затем в своем шаблоне вы должны сделать что-то вроде {{ getErrorMessage(register.errors) }}. Вы понимаете, что я пытаюсь сказать? :)

wentjun 09.04.2019 19:22

Ну, это исправляет часть этого, теперь проблема в том, что он проверяет это с каждым полем (имя получает недопустимую ошибку телефона), но я думаю, что это можно исправить, поместив эту строку только для тех, у кого есть дополнительная проверка. Обновление: я сделал это, и мы снова на один шаг ближе, теперь проблема, с которой я сталкиваюсь, заключается в том, что он показывает неправильную ошибку в этих полях, все получает недопустимую ошибку электронной почты

Mout Pessemier 10.04.2019 19:15

Другие вопросы по теме