typescript 密码确认角材料

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/50728460/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 05:28:18  来源:igfitidea点击:

Password Confirm Angular Material

javascripthtmlangulartypescriptangular-material

提问by LDB

I'm working to authenticate a user with Angular Material. I'm currently trying to get the proper mat-error to display when the confirmation password doesn't match the first entered pw.

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

Here is my html:

这是我的 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>

The error displays once the user has focused on password confirmation and unfocuses without entering anything. Once the user enters anything, the error goes away even though the confirmation doesn't match the password.

一旦用户专注于密码确认并且不输入任何内容就取消焦点,就会显示该错误。一旦用户输入任何内容,即使确认与密码不匹配,错误也会消失。

Here is my TS file:

这是我的 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));

The desired effect is that the error shows when the user has entered text into pw input when confirm pw is empty and to show an error when both have text but confirm doesn't match pw.

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

回答by weibeld

I solved it like this:

我是这样解决的:

Template:

模板:

  <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>

Component:

零件:

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);
  }
}

Validator:

验证器:

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

Notes:

笔记:

  • Thanks to onPasswordInput()being called from either password field, editing the first password field (and thus invalidating the password confirmation) also causes the mismatch error to be displayed in the password confirmation field.
  • The *ngIf="password2.invalid && !password2.hasError('required')"test for the password confirmation field ensures that never both error messages ("mismatch" and "required") are displayed at the same time.
  • 由于onPasswordInput()从任一密码字段调用,编辑第一个密码字段(从而使密码确认无效)也会导致密码确认字段中显示不匹配错误。
  • *ngIf="password2.invalid && !password2.hasError('required')"密码确认字段的测试确保永远不会同时显示两个错误消息(“不匹配”和“必需”)。

回答by G. Tranter

Based on your code, it doesn't look like you added any validation for the confirmPassword field: confirmPassword: new FormControl(null, )so the only validation happening is via the requiredattribute. Also, the mat-error will only be displayed by the form field if the form control is invalid. That means you can't force an error to be displayed just by using ngIf. Since you only have requiredvalidation on that field, it makes sense that you only have an error when the field is empty. To solve this problem, you need to create a validator for mismatch checking and add it to the confirmPassword form control. As an alternative, you can manually add errors to the form control using setErrors()when the field changes by adding an input listener - for example (this is just from memory - may need fixing):

根据您的代码,您似乎没有为 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);
    }
}

回答by Henry

you are essentially validating how 2 fields in a form interact with each other ("password" and "confirm password" fields). This is known as "cross-field validation"

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

that means, your custom validator cannot be assigned to just 1 field. The custom validator needs to be assigned to the common parent, the form.

这意味着,您的自定义验证器不能仅分配给 1 个字段。自定义验证器需要分配给常见的父级表单。

Here is the official documented best practice, for validating how 2 fields in a form interact with each other

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

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

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

this code snippet worked for me

这段代码对我有用

template:

模板:

<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:

组件.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 };
}

Note that for passwordMatchValidator, it is outside the component class. It is NOT inside the class

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

回答by Rob Lyndon

Henry's answer was very helpful (and I'm surprised it doesn't have more votes), but I've made a tweak to it so that it plays well with Angular Material controls.

亨利的回答非常有帮助(我很惊讶它没有更多投票),但我对其进行了调整,使其与 Angular Material 控件配合良好。

The tweak relies on the fact that the FormGroupclass has a parentproperty. Using this property, you can tie the validation message to the password confirmation field, and then refer up the chain in the validator.

调整依赖于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]]
  })
});

The validator looks like this:

验证器如下所示:

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 };
}

and the form then looks like this:

然后表格看起来像这样:

<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>