Я пытаюсь создать собственный валидатор в форме, управляемой моделью, это правильный способ его реализации

При реализации моего кода я получаю следующие ошибки в консоли

Ошибка: не удается найти элемент управления с именем: 'password' в _throwError (forms.js:1732) в setUpControl (forms.js:1640) в FormGroupDirective.push../node_modules/@angular/forms/fesm5/forms.js.FormGroupDirective.addControl (forms.js:4454) в FormControlName.push../node_modules/@angular/forms/fesm5/forms.js.FormControlName._setUpControl (forms.js:4959) в FormControlName.push../node_modules/@angular/forms/fesm5/forms.js.FormControlName.ngOnChanges (forms.js:4909) в checkAndUpdateDirectiveInline (core.js:9244) в checkAndUpdateNodeInline (core.js:10512) в checkAndUpdateNode (core.jsdUp47).js:11107) at debugCheckDirectivesFn (core.js:1106)

Я попытался создать новую группу форм, сгруппировав контроль над паролями и паролями, но у меня это не сработало.

Надстройка organization.ts

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';


@Component({
  selector: 'app-add-organization',
  templateUrl: './add-organization.component.html',
  styleUrls: ['./add-organization.component.css']
})
export class AddOrganizationComponent implements OnInit {

     myform: FormGroup;
     passwords: FormGroup;
     organizationName: FormControl;
     organizationAddress: FormControl;
     pinCode: FormControl;
     mobileNumber: FormControl;
     organizationType: string[] = ["WholeSale","Retail"];
     businessType: FormControl;
     ownerName: FormControl;
     password: FormControl;
     rePassword: FormControl;
     telephoneNumber: FormControl;
     gstin: FormControl;




  createFormControls() {

     this.organizationName = new FormControl("", Validators.required);
     this.ownerName = new FormControl("", Validators.required);
     this.organizationAddress = new FormControl("", Validators.required);
     this.pinCode = new FormControl("", Validators.required);
     this.mobileNumber = new FormControl("", Validators.required);
     this.telephoneNumber = new FormControl();
     this.businessType = new FormControl("", Validators.required);
     this.gstin = new FormControl("", [Validators.required]);
     this.passwords = new FormGroup({
      password: this.password = new FormControl("",[Validators.required,Validators.minLength(8)]),
      repassword: this.rePassword = new FormControl("",[Validators.required])
      },{ validators: this.passwordValidator }
      )
  }

  passwordValidator(fb: FormGroup) {
    let password  = fb.controls.password.value;
    let repass = fb.controls.repassword.value; 
      if (repass !== password) {
        return {
          passwordMatch: {
            passwordMatch: password
          }
        }
      }
    return null;
  } 

  createForm() {
    this.myform = new FormGroup({
    ownerName: this.ownerName,
    organizationName: this.organizationName,
    organizationAddress: this.organizationAddress,
    pinCode: this.pinCode,
    mobileNumber: this.mobileNumber,
    telephoneNumber: this.telephoneNumber,
    businessType: this.businessType,
    gstin: this.gstin,
    }); 
  }

  onSubmit() {
    if (this.myform.valid) {
      console.log("Form Submitted!");
      console.log(this.myform.value);
      this.myform.reset();
    }
  }


  constructor() { }

  ngOnInit() {
    this.createFormControls();
    this.createForm();
  }

}

надстройку organization.html

    <mat-form-field>
            <input matInput placeholder="Set password" type = "password" formControlName="password">
            <mat-error *ngIf="password.errors?.required">Password is required</mat-error>
            <mat-error *ngIf="password.errors?.minlength">
                Password must be {{password.errors.minlength.requiredLength}} characters long, we need another {{password.errors.minlength.requiredLength - password.errors.minlength.actualLength}} characters
            </mat-error>
          </mat-form-field>
          <mat-form-field>
            <input  matInput placeholder="Re-Enter password" type = "password" formControlName="rePassword">
            <mat-error *ngIf="rePassword.errors?.required">Password is required</mat-error>
            <mat-error *ngIf="passwords.validators.passwordValidator">not match</mat-error>
   </mat-form-field>

я ожидаю, что на выходе появится сообщение об ошибке, если и пароль, и повторный пароль не совпадают, иначе

3 ответа

Вы создали Form дважды. Однажды со всеми элементами управления в createFormControls(), Другой в createForm(), CreateForm не имеет password поле, таким образом, оно не создает элемент управления паролем, следовательно, HTML выдает ошибку при создании formControl с именем password,

Что вам нужно в createForm() является patchValue() обновить значение элементов управления, не меняя структуру формы.

Вот как я бы сделал это:

function passwordValidator() { // wrapper fn
  return (ctrl: AbstractControl) => { // return the function w abstractControl
    const fb = ctrl as FormGroup; //type it
    const passwordCtrl  = fb.get('password'); // get the ctrls
    const repassCtrl = fb.get('repassword'); 
    if (!passwordCtrl || !repassCtrl) // handle errors!
      throw new Error('need password and repass controls');
    if (passwordCtrl.value // make sure forms have values (required error should show in this case, not pass match)
          && repassCtrl.value 
          && repassCtrl.value !== passwordCtrl.value) {
      return {
        passwordMatch: password //redunant
      }
    }
    return null;
  }
}

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

{ validators: [passwordValidator()] }

однако ваша ошибка действительно возникает при создании группы:

this.passwords = new FormGroup({
  password: new FormControl("",[Validators.required,Validators.minLength(8)]),
  repassword: new FormControl("",[Validators.required])
  },{ validators: [passwordValidator()] }
)

вы просто не можете строить формы так, как вы это делали. Вы должны определить свой пароль и переменные repassword больше как это:

get password() { return this.passwords.get('password');
get repassword() { return this.passwords.get('repassword');

чтобы ошибка выглядела так, как она есть (внутри поля ошибки mat), вам нужно добавить эту странную вещь в ваш компонент:

parentErrorMatcher = {
  isErrorState(control: FormControl): boolean {
    return control.parent.invalid && control.touched;
  }
};

затем используйте его в шаблоне в поле формы, где вы хотите отобразить ошибку:

<mat-form-field [errorStateMatcher]="parentErrorMatcher">

это приведет к тому, что состояние ошибки будет отражать родителя, а не ребенка

Это только и советую. При создании formGroup вы можете использовать напрямую

this.myform = new FormGroup({
    ownerName: new FormControl('',Validators.Required),
    organizationName: new FormControl('',Validators.Required),
    organizationAddress: new FormControl('',Validators.Required),
    pinCode: new FormControl('',Validators.Required),
    mobileNumber: new FormControl('',Validators.Required),
    telephoneNumber: new FormControl(''),
    businessType: new FormControl('',Validators.Required),
    gstin: new FormControl('',Validators.Required),
    password:new FormGroup({
      password: new FormControl("",[Validators.required,Validators.minLength(8)]),
      repassword: this.rePassword = new FormControl("",[Validators.required])
      },{ validators: this.passwordValidator }
      )
    }); 

Если вы используете {validators:this.passwordValidator}, ваша функция объявляется как

passwordValidator(formGroup:FromGroup)
{ 
     ....
}

Если вы используете { validators: this.passwordValidator() } //<- см. ()

passwordValidator()
{
  return (formGroup:FromGroup)=>
  { 
     ....
  }
}