パスワードとパスワード確認が等しいかどうかを確認するためのカスタムバリデーターを実装しようとしています。問題は、バリデーターが未定義のパスワードとconfirmPasswordパラメーターを取得していることです。この作業を行うにはどうすればよいですか。関数は、条件を!==ではなく===に変更すると、フィールドが同じ場合にエラーを正しくスローするため、機能します。誰がここのエラーを知っていますか?
signup.component.html
<div class="col-md-7 col-md-offset-1 col-sm-7">
<div class="block">
<div class="well">
<form (onSubmit)="onSubmit()" [formGroup]="signUpForm">
<div class="form-group">
<label for="username" class="control-label">Nombre de usuario:</label>
<input type="text" class="form-control" formControlName="username" title="Please enter your username" placeholder="username">
<p class="help-block" *ngIf="signUpForm.get('username').hasError('required') && signUpForm.get('username').touched">El nombre de usuario es obligatorio</p>
<p class="help-block" *ngIf="signUpForm.get('username').hasError('minlength') && signUpForm.get('username').touched">El nombre de usuario debe tener al menos 6 caracteres</p>
<p class="help-block" *ngIf="signUpForm.get('username').hasError('maxlength') && signUpForm.get('username').touched">El nombre de usuario debe tener menos de 15 caracteres</p>
</div>
<div class="form-group">
<label for="email" class="control-label">E-mail:</label>
<input class="form-control" formControlName="email" title="Please enter your email" placeholder="[email protected]">
<p class="help-block" *ngIf="signUpForm.get('email').hasError('required') && signUpForm.get('email').touched">La dirección de email es obligatoria</p>
<p class="help-block" *ngIf="signUpForm.get('email').hasError('email') && signUpForm.get('email').touched">Debe ingresar una dirección de correo válida</p>
</div>
<div class="form-group">
<label for="password" class="control-label">Contraseña:</label>
<input type="password" class="form-control" formControlName="password" title="Please enter your password" [(ngModel)]="password">
<p class="help-block" *ngIf="signUpForm.get('password').hasError('required') && signUpForm.get('password').touched">Debe ingresar una contraseña</p>
</div>
<div class="form-group">
<label for="confirmedPassword" class="control-label">Confirmar Contraseña:</label>
<input type="password" class="form-control" formControlName="confirmedPassword" title="Please re-enter your password" [(ngModel)]="confirmedPassword">
<p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('required') && signUpForm.get('confirmedPassword').touched">La confirmación de contraseña no puede estar vacía</p>
<p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('passwordMismatch') && signUpForm.get('confirmedPassword').touched">Las contraseñas no coinciden</p>
</div>
<button type="submit" class="btn btn-success" [disabled]="!signUpForm.valid">Registrarse</button>
<a routerLink="/signin" class="btn btn-default" style="">Ya tenes usuario? Logueate</a> {{ creationMessage }}
</form>
</div>
</div>
</div>
signup.component.ts
import { Component, OnInit, ViewChild, Input } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { CustomValidators } from '../../shared/custom-validators';
import { Observable } from 'rxjs/Observable';
@Component({
selector: 'app-signup',
templateUrl: './signup.component.html',
styleUrls: ['./signup.component.sass']
})
export class SignupComponent implements OnInit {
signUpForm: FormGroup;
user = {
username: '',
email: '',
password: ''
};
submitted = false;
@Input() password='';
@Input() confirmedPassword='';
constructor() { }
ngOnInit() {
this.signUpForm = new FormGroup({
'username': new FormControl(null, [Validators.required, Validators.minLength(6), Validators.maxLength(15)]),
'email': new FormControl(null, [Validators.required, Validators.email, Validators.minLength(5)]),
'password': new FormControl(null, [Validators.required]),
'confirmedPassword': new FormControl(null, [Validators.required, CustomValidators.passwordsMatch(this.password,this.confirmedPassword).bind(this)])
});
}
onSubmit() {
if (this.signUpForm.valid) {
console.log(this.signUpForm.value);
}
}
}
custom-validators.ts
import { FormControl } from '@angular/forms';
export class CustomValidators{
public static passwordsMatch(password: string, confirmedPassword: string) {
return (control: FormControl) : { [s: string]: boolean } =>{
//getting undefined values for both variables
console.log(password,confirmedPassword);
//if I change this condition to === it throws the error if the
// two fields are the same, so this part works
if (password !== confirmedPassword) {
return { 'passwordMismatch': true }
} else {
//it always gets here no matter what
return null;
}
}
}
}
インポート{AbstractControl、FormBuilder、FormGroup、Validators}
グループにパスワード入力を設定し、「ngModel」を使用する必要はありません。
<div class="form-group row" formGroupName="passwords">
<div class="form-group">
<label for="password" class="control-label">Contraseña:</label>
<input type="password" class="form-control" formControlName="password" title="Please enter your password">
<p class="help-block" *ngIf="signUpForm.get('password').hasError('required') && signUpForm.get('password').touched">Debe ingresar una contraseña</p>
</div>
<div class="form-group">
<label for="confirmedPassword" class="control-label">Confirmar Contraseña:</label>
<input type="password" class="form-control" formControlName="confirmedPassword" title="Please re-enter your password">
<p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('required') && signUpForm.get('confirmedPassword').touched">La confirmación de contraseña no puede estar vacía</p>
<p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('passwordMismatch') && signUpForm.get('confirmedPassword').touched">Las contraseñas no coinciden</p>
</div>
buildForm(): void {
this.userForm = this.formBuilder.group({
passwords: this.formBuilder.group({
password: ['', [Validators.required]],
confirm_password: ['', [Validators.required]],
}, {validator: this.passwordConfirming}),
});
}
パスワードの検証とパスワードの確認のためにこのカスタム関数を追加します
passwordConfirming(c: AbstractControl): { invalid: boolean } {
if (c.get('password').value !== c.get('confirm_password').value) {
return {invalid: true};
}
}
パスワードが一致しない場合に表示エラー
<div style='color:#ff7355' *ngIf="userForm.get(['passwords','password']).value != userForm.get(['passwords','confirm_password']).value && userForm.get(['passwords','confirm_password']).value != null">
Password does not match</div>
問題は、あなたがReactive Formsモジュールと入力アプローチを組み合わせているであることです。これにより、値をバリデータに渡すときにundefined
が取得されます。
リアクティブフォームを使用する場合、ng-model
にバインドする必要はありません。代わりに、FormGroup
のインスタンスからフィールドの値にアクセスする必要があります。
アプリでこのようなことをして、パスワードの一致を検証します。
public Credentials: FormGroup;
ngOnInit() {
this.Credentials = new FormGroup({});
this.Credentials.addControl('Password', new FormControl('', [Validators.required]));
this.Credentials.addControl('Confirmation', new FormControl(
'', [Validators.compose(
[Validators.required, this.validateAreEqual.bind(this)]
)]
));
}
private validateAreEqual(fieldControl: FormControl) {
return fieldControl.value === this.Credentials.get("Password").value ? null : {
NotEqual: true
};
}
バリデーターはパラメーターとしてFormControl
フィールドを予期し、フィールドの値をPassword
Credentials
のFormGroup
フィールドの値と比較することに注意してください。
HTML
で、必ずng-model
を削除してください。
<input type="password" class="form-control" formControlName="confirmedPassword" title="Please re-enter your password" >
<!-- AND -->
<input type="password" class="form-control" formControlName="password" title="Please enter your password">
お役に立てれば!
バリデーターには2つのタイプがあります:FormGroupバリデーターおよびFormControlバリデーター。 2つのパスワードが一致することを確認するには、FormGroupバリデーターを追加する必要があります。以下は私の例です:
注:this.fbは注入されたFormBuilderです
this.newAccountForm = this.fb.group(
{
newPassword: ['', [Validators.required, Validators.minLength(6)]],
repeatNewPassword: ['', [Validators.required, Validators.minLength(6)]],
},
{validator: this.passwordMatchValidator}
);
passwordMatchValidator(frm: FormGroup) {
return frm.controls['newPassword'].value === frm.controls['repeatNewPassword'].value ? null : {'mismatch': true};
}
そしてテンパレートで:
<div class="invalid-feedback" *ngIf="newAccountForm.errors?.mismatch && (newAccountForm.controls['repeatNewPassword'].dirty || newAccountForm.controls['repeatNewPassword'].touched)">
Passwords don't match.
</div>
キーポイントは、FormGroupバリデーターを2番目のパラメーターとしてグループメソッドに追加することです。
Angular5でFormGroupコードを以下のように更新してください
this.signUpForm = new FormGroup({
'username': new FormControl(null, [Validators.required, Validators.minLength(6), Validators.maxLength(15)]),
'email': new FormControl(null, [Validators.required, Validators.email, Validators.minLength(5)]),
'password': new FormControl(null, [Validators.required]),
'confirmedPassword': new FormControl(null, [Validators.required])
}, this.pwdMatchValidator);
コンポーネントにpwdMatchValidator
関数を追加します
pwdMatchValidator(frm: FormGroup) {
return frm.get('password').value === frm.get('confirmedPassword').value
? null : {'mismatch': true};
}
テンプレートに検証メッセージを追加します
<span *ngIf="confirmedPassword.errors || signUpForm .errors?.mismatch">
Password doesn't match
</span>
以下のangular材料作業コンポーネントを見つけてください。
コンポーネントテンプレートコードpassword.component.html
<form class="cahnge-pwd-form" (ngSubmit)="onSubmit()" name="passwordForm" [formGroup]="passwordForm" #formDir="ngForm">
<div fxLayout='column'>
<mat-form-field>
<input matInput name="password" placeholder="Password" [type]="hide ? 'text' : 'password'" formControlName="password" required>
<mat-icon matSuffix (click)="hide = !hide">{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
<mat-error *ngIf="password.invalid && (password.dirty || password.touched || isSubmit)">
<span *ngIf="password.errors.required">
Please enter a Password.
</span>
<span *ngIf="password.errors.maxlength">
Please enter a Email no more than 16 characters.
</span>
<span *ngIf="password.errors.minlength">
Please enter a password at least 6 characters.
</span>
</mat-error>
</mat-form-field>
<mat-form-field>
<input matInput name="password" placeholder="Confirm Password" [type]="confirm_hide ? 'text' : 'password'" formControlName="confirm_password"
required>
<mat-icon matSuffix (click)="confirm_hide = !confirm_hide">{{confirm_hide ? 'visibility_off' : 'visibility'}}</mat-icon>
<mat-error *ngIf="(confirm_password.invalid && (confirm_password.dirty || confirm_password.touched || isSubmit) || passwordForm.errors?.mismatch)">
<span *ngIf="confirm_password.errors || passwordForm.errors?.mismatch">
Password doesn't match
</span>
</mat-error>
</mat-form-field>
<div fxLayout='row' fxLayoutGap="10px">
<button type="submit" mat-raised-button color="primary">Submit</button>
<button type="button" (click)="formDir.resetForm(passwordForm)" mat-raised-button color="warn">Cancel</button>
</div>
</div>
</form>
コンポーネントコード:password.component.ts
import { Component, OnInit, AfterViewInit } from '@angular/core';
import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
import { PasswordService } from './password.service';
import { PasswordValidation } from './confirm';
@Component({
selector: 'app-password',
templateUrl: './password.component.html',
styleUrls: ['./password.component.css']
})
export class PasswordComponent implements OnInit {
passwordForm: FormGroup;
isSubmit: boolean;
constructor(private router: Router, private passwordService: PasswordService, private toastrService: ToastrService, private route: ActivatedRoute) { }
ngOnInit() {
this.passwordForm = new FormGroup({
'password': new FormControl('', [
Validators.required,
Validators.minLength(6),
Validators.maxLength(16),
]),
'confirm_password': new FormControl('', [
Validators.required,
Validators.minLength(6),
Validators.maxLength(16),
]),
}, this.pwdMatchValidator);
}
pwdMatchValidator(frm: FormGroup) {
return frm.get('password').value === frm.get('confirm_password').value
? null : {'mismatch': true};
}
get password() { return this.passwordForm.get('password'); }
get confirm_password() { return this.passwordForm.get('confirm_password'); }
onSubmit(formvalue):boolean {
this.isSubmit = true;
if (this.passwordForm.invalid) {
return false;
} else {
this.passwordService.updatePassword(this.passwordForm.value)
.subscribe((res) => {
if (res.status == 'success') {
this.toastrService.success(res.msg);
this.router.navigate(['/change-password']);
}
})
return true;
}
}
}
複数のフィールドで検証する必要があり、フォーム作成時にバリデーターを宣言する場合、FormGroup validatorを使用する必要があります。フォームバリデータの主な問題は、コントロールの検証ではなくフォームにエラーを添付することです。これは、テンプレートの一部の矛盾に依存します。以下は、フォームとコントロールの両方にエラーを付加する再利用可能なフォームバリデーターです。
// in validators.ts file
export function controlsEqual(
controlName: string,
equalToName: string,
errorKey: string = controlName // here you can customize validation error key
) {
return (form: FormGroup) => {
const control = form.get(controlName);
if (control.value !== form.get(equalToName).value) {
control.setErrors({ [errorKey]: true });
return {
[errorKey]: true
}
} else {
control.setErrors(null);
return null
}
}
}
// then you can use it like
ngOnInit() {
this.vmForm = this.fb.group({
username: ['', [Validators.required, Validators.email]],
password: ['', [
Validators.required,
Validators.pattern('[\\w\\d]+'),
Validators.minLength(8)]],
confirm: [''], // no need for any validators here
}, {
// here we attach our form validator
validators: controlsEqual('confirm', 'password')
});
}
Shailesh Ladumorと同じですが、検証関数に戻る前に次の行を追加します。
c.get('confirm_password').setErrors({'noMatch': true});
検証関数は次のようになります。
passwordConfirming(c: AbstractControl): { invalid: boolean } {
if (c.get('password').value !== c.get('confirm_password').value) {
c.get('confirm_password').setErrors({'noMatch': true});
return {invalid: true};
}
}
これは、穴userForm
を無効なフォームグループとして設定するだけでなく、confirm_password
を無効なフォームコントロールとして設定します。
これにより、後でテンプレートで次の関数を呼び出すことができます。
public getPasswordConfirmationErrorMessage() {
if (this.userForm.get('confirm_password').hasError('required')) {
return 'You must retype your password';
} else if (this.userForm.get('confirm_password').hasError('noMatch')) {
return 'Passwords do not match';
} else {
return '';
}
}
バリデーターを作成するとき、password
とconfirmedPassword
の値を渡しますが、これらの値の変更はバリデーターに反映されません。
表示される2つのオプションは次のとおりです。
FormGroup
でバリデータを定義し、比較する2つのコントロールから値を検索します。またはthis
にバインドしているため、バリデーターでthis.password
とthis.confirmedPassword
を使用します。