密码确认角度材料

时间:2018-06-06 19:50:06

标签: javascript html angular typescript angular-material

我正在尝试使用Angular Material对用户进行身份验证。当确认密码与第一个输入的pw不匹配时,我正在尝试显示正确的mat-error。

这是我的HTML:

 <mat-form-field hintLabel="Minimum 8 Characters" class="">
                            <mat-label>Password</mat-label>
                            <input 
                            matInput 
                            #input 
                            type="password"
                            formControlName="password">
                            <mat-hint align="end">{{input.value?.length || 0}}/8</mat-hint>
                        </mat-form-field>

                        <mat-form-field>
                            <mat-label>Confirm</mat-label>
                            <input 
                            matInput
                            required  
                            type="password"
                            #confirm
                            formControlName="confirmPassword">
                            <mat-error *ngIf="form.get('confirmPassword').invalid || confirmPasswordMismatch">Password does not match</mat-error>
                            </mat-form-field>

一旦用户专注于密码确认并取消注意而不输入任何内容,则会显示错误。一旦用户输入任何内容,即使确认信息与密码不匹配,错误也会消失。

这是我的TS文件:

public get confirmPasswordMismatch() {
        return (this.form.get('password').dirty || this.form.get('confirmPassword').dirty) && this.form.hasError('confirmedDoesNotMatch');
    }

this.form = new FormGroup({
            userName: new FormControl(null, [Validators.required]),
            fullName: new FormControl(null, [Validators.required]),
            email: new FormControl(null, [Validators.required, Validators.pattern(this.EMAIL_REGEX)]),
            password: new FormControl(null),
            confirmPassword: new FormControl(null, ),
        }, (form: FormGroup) => passwordValidator.validate(form));

期望的效果是当用户在确认pw为空时将文本输入到pw输入时显示错误,并且当两者都有文本但是确认不匹配pw时显示错误。

4 个答案:

答案 0 :(得分:4)

根据您的代码,您似乎没有为confirmPassword字段添加任何验证:confirmPassword: new FormControl(null, )因此唯一的验证是通过required属性进行的。此外,如果表单控件无效,则只会通过表单字段显示mat-error。这意味着您不能仅使用ngIf强制显示错误。由于您只对该字段进行了required验证,因此只有在字段为空时才会出现错误。要解决此问题,您需要为不匹配检查创建验证器并将其添加到confirmPassword表单控件。作为替代方案,当字段通过添加输入侦听器而更改时,可以使用setErrors()手动向表单控件添加错误 - 例如(这只是来自内存 - 可能需要修复):

<mat-form-field>
    <mat-label>Confirm</mat-label>
    <input matInput required type="password" #confirm formControlName="confirmPassword"
        (input)="onInput($event.target.value)">
    <mat-error *ngIf="form.get('confirmPassword').invalid>
        Password does not match
    </mat-error>
</mat-form-field>


onInput(value) {
    if (this.form.hasError('confirmedDoesNotMatch')) { // or some other test of the value
        this.form.get('confirmPassword').setErrors([{'confirmedDoesNotMatch': true}]);
    } else {
        this.form.get('confirmPassword').setErrors(null);
    }
}

答案 1 :(得分:2)

我这样解决了:

模板:

  <mat-form-field>
    <input matInput type="password" placeholder="Password" formControlName="password" (input)="onPasswordInput()">
    <mat-error *ngIf="password.hasError('required')">Password is required</mat-error>
    <mat-error *ngIf="password.hasError('minlength')">Password must have at least {{minPw}} characters</mat-error>
  </mat-form-field>

  <mat-form-field>
    <input matInput type="password" placeholder="Confirm password" formControlName="password2" (input)="onPasswordInput()">
    <mat-error *ngIf="password2.hasError('required')">Please confirm your password</mat-error>
    <mat-error *ngIf="password2.invalid && !password2.hasError('required')">Passwords don't match</mat-error>
  </mat-form-field>

组件:

export class SignUpFormComponent implements OnInit {

  minPw = 8;
  formGroup: FormGroup;

  constructor(private formBuilder: FormBuilder) { }

  ngOnInit() {
    this.formGroup = this.formBuilder.group({
      password: ['', [Validators.required, Validators.minLength(this.minPw)]],
      password2: ['', [Validators.required]]
    }, {validator: passwordMatchValidator});
  }

  /* Shorthands for form controls (used from within template) */
  get password() { return this.formGroup.get('password'); }
  get password2() { return this.formGroup.get('password2'); }

  /* Called on each input in either password field */
  onPasswordInput() {
    if (this.formGroup.hasError('passwordMismatch'))
      this.password2.setErrors([{'passwordMismatch': true}]);
    else
      this.password2.setErrors(null);
  }
}

验证者:

export const passwordMatchValidator: ValidatorFn = (formGroup: FormGroup): ValidationErrors | null => {
  if (formGroup.get('password').value === formGroup.get('password2').value)
    return null;
  else
    return {passwordMismatch: true};
};

注释:

  • 由于要从任一密码字段中调用onPasswordInput(),因此编辑第一个密码字段(从而使密码确认无效)也会导致不匹配错误显示在密码确认字段中。
  • *ngIf="password2.invalid && !password2.hasError('required')"密码确认字段的测试可确保永远不会同时显示两个错误消息(“不匹配”和“必需”)。

答案 2 :(得分:1)

Henry的回答非常有帮助(我很惊讶它没有更多的选票),但是我对其进行了调整,以便它与Angular Material控件配合使用。

该调整取决于FormGroup类具有parent属性的事实。使用此属性,可以将验证消息绑定到密码确认字段,然后在验证器中向上引用链。

public signUpFormGroup: FormGroup = this.formBuilder.group({
  email: ['', [Validators.required, Validators.pattern(validation.patterns.email)]],
  newPassword: this.formBuilder.group({
    password: ['', [
      Validators.required,
      Validators.minLength(validation.passwordLength.min),
      Validators.maxLength(validation.passwordLength.max)]],
    confirmPassword: ['', [Validators.required, passwordMatchValidator]]
  })
});

验证器如下:

export const passwordMatchValidator: ValidatorFn = (formGroup: FormGroup): ValidationErrors | null => {
  const parent = formGroup.parent as FormGroup;
  if (!parent) return null;
  return parent.get('password').value === parent.get('confirmPassword').value ?
    null : { 'mismatch': true };
}

,表单如下所示:

<div formGroupName="newPassword" class="full-width new-password">
  <mat-form-field class="full-width sign-up-password">
    <mat-label>{{ 'sign-up.password' | translate }}</mat-label>
    <input matInput [type]="toggleSignUpPass.type" [maxlength]="max" [minlength]="min" formControlName="password" required/>
    <mat-pass-toggle-visibility #toggleSignUpPass matSuffix></mat-pass-toggle-visibility>
    <mat-icon matSuffix [color]="color$ | async">lock</mat-icon>
    <mat-hint aria-live="polite">{{ signUpFormGroup.get('newPassword').value.password.length }}
      / {{ max }} </mat-hint>
    <mat-error *ngIf="signUpFormGroup?.get('newPassword')?.controls?.password?.hasError('required')">
      {{ 'sign-up.password-error.required' | translate }}
    </mat-error>
    <mat-error class="password-too-short" *ngIf="signUpFormGroup?.get('newPassword')?.controls?.password?.hasError('minlength')">
      {{ 'sign-up.password-error.min-length' | translate:passwordRestriction.minLength }}
    </mat-error>
    <mat-error *ngIf="signUpFormGroup?.get('newPassword')?.controls?.password?.hasError('maxlength')">
      {{ 'sign-up.password-error.max-length' | translate:passwordRestriction.maxLength }}
    </mat-error>
  </mat-form-field>
  <mat-form-field class="full-width sign-up-confirm-password">
    <mat-label>{{ 'sign-up.confirm-password' | translate }}</mat-label>
    <input matInput [type]="toggleSignUpPassConf.type" formControlName="confirmPassword" required />
    <mat-pass-toggle-visibility #toggleSignUpPassConf matSuffix></mat-pass-toggle-visibility>
    <mat-icon matSuffix [color]="color$ | async">lock</mat-icon>
    <mat-error *ngIf="signUpFormGroup?.get('newPassword')?.controls?.confirmPassword?.hasError('required')">
      {{ 'sign-up.confirm-password-error.required' | translate }}
    </mat-error>
    <mat-error class="password-mismatch" *ngIf="signUpFormGroup?.get('newPassword')?.controls?.confirmPassword?.hasError('mismatch')">
      {{ 'sign-up.password-error.mismatch' | translate }}
    </mat-error>
  </mat-form-field>
</div>

答案 3 :(得分:0)

实际上,您正在验证表单中的两个字段如何相互交互(“密码”和“确认密码”字段)。这称为“ 跨领域验证

这意味着您的自定义验证器不能仅分配给1个字段。需要将自定义验证器分配给公共父窗体,即表单。

这是官方记录的最佳实践,用于验证表单中的2个字段如何相互影响

https://angular.io/guide/form-validation#cross-field-validation

此代码段对我有用

模板:

<form method="post" [formGroup]="newPasswordForm">
  <input type="password" formControlName="newPassword" />
  <input type="password" formControlName="newPasswordConfirm" />
  <div class="err-msg" *ngIf="newPasswordForm.errors?.passwordMismatch && (newPasswordForm.touched || newPasswordForm.dirty)">
        confirm-password does not match password
      </div>
</form>

component.ts:

export class Component implements OnInit {
    this.newPasswordForm = new FormGroup({
      'newPassword': new FormControl('', [
        Validators.required,
      ]),
      'newPasswordConfirm': new FormControl('', [
        Validators.required
      ])
    }, { validators: passwordMatchValidator });
}

export const passwordMatchValidator: ValidatorFn = (formGroup: FormGroup): ValidationErrors | null => {
  return formGroup.get('newPassword').value === formGroup.get('newPasswordConfirm').value ?
    null : { 'passwordMismatch': true };
}

请注意,对于passwordMatchValidator,它在组件类之外。它不在课程之内