【问题标题】:How can I trigger validations for inputs in ReactiveForms?如何触发对响应式表单中的输入的验证?
【发布时间】:2021-12-04 08:56:15
【问题描述】:

我在 Reactive Forms 中开发了一个表单,用户可以在其中设置新密码。他输入旧密码和新密码并确认新密码。 我考虑过以下情况:

  • 新密码不能包含旧密码
  • 新密码和确认密码匹配

开发同样有效。现在我有一件不好的事情。仅当我在输入字段中更改某些内容时才会触发验证。但是现在想确认密码的时候想改新密码,这样就知道有没有错误了。我读过这可以通过函数 updateValueAndValidity 来完成。你知道怎么做吗?

我的代码:

// TS
changePasswordForm: FormGroup;
submitted = false;

ngOnInit() {
    // To initialize forms
    this.initChangePasswordForm();
  }

  // Creation of the changePasswordForm
  private initChangePasswordForm() {
    // General
    this.changePasswordForm = this.formBuilder.group({
      old_password: [null, Validators.pattern('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\\w\\s]).{8,}$')],
      new_password: [null, this.customComparePasswordValidator],
      confirm_password: [null, Validators.required]
    });
  }

 customComparePasswordValidator(control: FormControl) {
    const newPassword = control.value;
    if (newPassword && newPassword.length) {
      const oldPassword = control.parent.value.old_password;
      if (oldPassword && oldPassword.length && newPassword.toLowerCase().includes(oldPassword.toLowerCase())) {
        return { newPasswordIncludesOldPassword: true };
      }
      const pattern = new RegExp('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\\w\\s]).{8,}$');
      if (!pattern.test(newPassword)) {
        return { newPasswordInvalid: true };
      }
    } else {
      return { required: true };
    }
  }
// HTML
<input matInput type="password" placeholder="aktuelles Passwort" formControlName="old_password" required>
 <p *ngIf="changePasswordForm.get('old_password').invalid && (changePasswordForm.get('old_password').dirty || changePasswordForm.get('old_password').touched)">
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('old_password').hasError('required')">aktuelles Passwort eingeben</mat-error>
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('old_password').hasError('pattern')">8 oder mehr Zeichen mit einer Mischung aus Groß- und Kleinbuchstaben, Ziffern und Symbolen verwenden</mat-error>
          </p>

<input matInput type="password" placeholder="neues Passwort" formControlName="new_password" required>
<p *ngIf="changePasswordForm.get('new_password').invalid && (changePasswordForm.get('new_password').dirty || changePasswordForm.get('new_password').touched)">
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('new_password').hasError('required')">neues Passwort eingeben</mat-error>
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('new_password').hasError('newPasswordInvalid')">8 oder mehr Zeichen mit einer Mischung aus Groß- und Kleinbuchstaben, Ziffern und Symbolen verwenden</mat-error>
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('new_password').hasError('newPasswordIncludesOldPassword')">Neues und altes Passwort dürfen nicht gleich sein</mat-error>
          </p>

 <input matInput type="password" placeholder="Passwort bestätigen" formControlName="confirm_password" appConfirmEqualValidator="new_password" required>
 <p *ngIf="changePasswordForm.get('confirm_password').invalid && (changePasswordForm.get('confirm_password').dirty || changePasswordForm.get('confirm_password').touched)">
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('confirm_password').hasError('required')">Passwort erneut eingeben</mat-error>
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('confirm_password').hasError('notEqual') && !changePasswordForm.get('confirm_password').hasError('required')">Passwort stimmt nicht überein</mat-error>
          </p>

我的 StackBlitz:https://stackblitz.com/edit/example-angular-material-reactive-form-sr1keu?file=app%2Fapp.component.html

【问题讨论】:

    标签: angular typescript validation angular-reactive-forms


    【解决方案1】:

    正如您所说,验证器仅在您更改 FormControl 时“检查”。因此,您可以在更改第二个控件时“强制”使一个控件生效。所以,例如你只需要做,在FormControl“new_password”中写

    <input matInput ... formControlName="new_password"
         (input)="changePasswordForm.get('confirm_password').updateValueAndValidity()"  />
    

    (与其他 FormControl 同上)

    你也可以在创建表单后订阅valueChanges-别忘了取消订阅-

      private initChangePasswordForm() {
        // After create the formGroup
        this.changePasswordForm = this.formBuilder.group({..}
    
        //subscribe to changes "new_password"
        this.changePasswordForm.get('new_password').valueChanges
           .subscribe(_=>{
                this.changePasswordForm.get('confirm_password').updateValueAndValidity()     
        })
    

    另一种方法是在整个表单上创建一个 customValidator。当你使用材料时,你需要使用 setErrors。验证器可以像

      validatorRepeatPassword(form: FormGroup) {
        const errorOldPassword = {};
        const errorNewPassword = {};
        const errorConfirmPassword = {};
        const pattern = new RegExp(
          '^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\\w\\s]).{8,}$'
        );
        if (!form.value.old_password) errorOldPassword['required'] = true;
        else {
          if (!pattern.test(form.value.old_password))
            errorOldPassword['pattern'] =
              '8 or more characters with a mixture of upper and lower case letters,use numbers and symbols';
        }
        if (!form.value.new_password) errorNewPassword['required'] = true;
        else {
          if (!pattern.test(form.value.new_password))
            errorNewPassword['pattern'] =
              '8 or more characters with a mixture of upper and lower case letters,use numbers and symbols';
          if (
            form.value.old_password &&
            form.value.new_password
              .toLowerCase()
              .includes(form.value.old_password.toLowerCase())
          )
            errorNewPassword['newPasswordIncludesOldPassword'] = true;
        }
        if (!form.value.confirm_password) errorConfirmPassword['required'] = true;
        else {
          if (
            form.value.new_password &&
            form.value.confirm_password != form.value.new_password
          )
            errorConfirmPassword['notEqual'] = true;
        }
        form.controls.old_password.setErrors(
          Object.keys(errorOldPassword).length ? errorOldPassword : null
        );
        form.controls.new_password.setErrors(
          Object.keys(errorNewPassword).length ? errorNewPassword : null
        );
        form.controls.confirm_password.setErrors(
          Object.keys(errorConfirmPassword).length ? errorConfirmPassword : null
        );
        return {
          ...errorOldPassword,
          ...errorNewPassword,
          ...errorConfirmPassword,
        };
      }
    

    并使用

    this.changePasswordForm = this.formBuilder.group(
      {
        old_password: null,
        new_password: null,
        confirm_password: null,
      },
      { validator: this.validatorRepeatPassword }
    );
    

    最后一种方法(我只用 new_password 和确认密码做验证器用这两个控件。像这样的函数

      matchValidator(field: string,not:boolean=false) {
        return (control: AbstractControl) => {
          const parent = control.parent;
          const controlCompare = parent ? parent.get(field) : null;
          if (controlCompare && controlCompare.value && control.value) {
            const invalid = controlCompare.value != control.value;
            if (invalid!=controlCompare.invalid)
            {
              setTimeout(()=>{
                controlCompare.updateValueAndValidity();
    
              })
            }
    
            return invalid && !not ? { match: 'no match' } : null;
          }
        };
      }
    

    请允许我们写,例如

    this.changePasswordForm = this.formBuilder.group(
      {
        old_password: null,
        new_password: [null,this.matchValidator('confirm_password',true)],
        confirm_password: [null,this.matchValidator('confirm_password',true)]
      }
    );
    

    看到你使用一个函数来传递参数-应该是固定的-

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-17
      • 2019-03-19
      • 2023-04-02
      • 2014-09-03
      • 1970-01-01
      • 2021-08-20
      相关资源
      最近更新 更多