Angular 2 формы для повторения пароля
Пожалуйста, обратитесь к question в отношении Сравнение полей в валидаторе с angular2. К сожалению, Angular 2 немного изменился, так что решение, похоже, больше не работает. Вот мой код:
import {IonicApp,Page,NavController,NavParams} from 'ionic/ionic'
import {Component} from 'angular2/core'
import {FORM_PROVIDERS, FormBuilder, Validators} from 'angular2/common'
import {ControlMessages} from '../../components/control-messages'
import {ValidationService} from '../../services/validation-service'
@Page({
templateUrl: 'build/pages/account/register.html',
directives: [ControlMessages]
})
export class RegisterPage {
constructor(nav:NavController,private builder: FormBuilder) {
this.nav = nav
this.registerForm = this.builder.group({
'name' : ['', Validators.required],
'email' : ['',Validators.compose([Validators.required, ValidationService.emailValidator])],
'password' : ['',Validators.required],
'repeat' : ['',this.customValidator]
}
)
}
register() {
alert(this.registerForm.value.password)
}
private customValidator(control) {
//console.log(this.registerForm.value.password)
//return {isEqual: control.value === this.registerForm.value.password}
return true
}
}
Мой html:
<ion-content class="account">
<ion-list padding>
<form [ngFormModel]='registerForm' (submit)='register()'>
<div class="centered">
<img class="logo" src="img/logo.png" alt="">
</div>
<div class="spacer" style="height: 20px;"></div>
<ion-input>
<ion-label floating>Name</ion-label>
<input type="text" ngControl='name' id='name'>
<control-messages control="name"></control-messages>
</ion-input>
<ion-input>
<ion-label floating>Email</ion-label>
<input type="email" ngControl='email' id='email'>
<control-messages control="email"></control-messages>
</ion-input>
<ion-input>
<ion-label floating>Password</ion-label>
<input type="password" ngControl='password' id='password' value="">
<control-messages control="password"></control-messages>
</ion-input>
<ion-input>
<ion-label floating>Confirm Password</ion-label>
<input type="password" ngControl='repeat' id='repeat'>
<control-messages control="repeat"></control-messages>
</ion-input>
<button class="calm" full type='submit' [disabled]='!registerForm.valid'>Register</button>
<ion-item style="background-color:transparent;border:none;">
<button class="text-button" clear item-right (click)="gotoLogin()">Have an account already, Login</button>
</ion-item>
</form>
</ion-list>
</ion-content>
Но, к сожалению, я не могу получить доступ к значению "password" в моей функции проверки. Если я раскомментирую console.log(this.registerForm.value.password), я получил следующее сообщение об ошибке:
ИСКЛЮЧЕНИЕ: TypeError: не может прочитать значение свойства 'undefined
Любая идея? Спасибо.
Ответы
Ответ 1
Я вижу несколько проблем в вашем коде. Вы пытаетесь использовать ключевое слово this
в функции проверки подлинности, и это не соответствует экземпляру компонента. Это потому, что вы ссылаетесь на функцию при ее установке в качестве функции валидатора.
Кроме того, значение, связанное с элементом управления, может быть достигнуто в свойстве value
.
Тем не менее, я думаю, что правильный способ проверить ваши два поля вместе - это создать группу и связать с ней валидатор:
this.registerForm = this.builder.group({
'name' : ['', Validators.required],
'email' : ['',Validators.compose([Validators.required,
ValidationService.emailValidator])],
'passwords': fb.group({
password: ['', Validators.required],
repeat: ['', Validators.required]
}, {validator: this.areEqual})
});
Таким образом, у вас будет доступ ко всем элементам управления группы, а не только к одному, и больше не нужно использовать ключевое слово this
... Доступ к нему можно получить, используя свойство controls
группового элемента управления. Последний (не один) напрямую предоставляется при срабатывании проверки. Например:
areEqual(group: ControlGroup) {
var valid = false;
for (name in group.controls) {
var val = group.controls[name].value
(...)
}
if (valid) {
return null;
}
return {
areEqual: true
};
}
Смотрите этот андер для получения дополнительной информации:
Edit
Чтобы отобразить эту ошибку, вы можете просто использовать следующее:
<span *ngIf="!registerForm.passwords.valid" class="help-block text-danger">
<div *ngIf="registerForm.passwords?.errors?.areEqual">
The two passwords aren't the same
</div>
</span>
Ответ 2
Я выполнил специальный валидатор для проверки паролей для Angular 4.
Помимо проверки соответствия двух значений, он также подписывается на изменения от другого элемента управления и повторно проверяет, обновляется ли один из двух элементов управления. Не стесняйтесь использовать его в качестве ссылки для своей собственной реализации или просто скопируйте ее напрямую.
Здесь ссылка на решение: https://gist.github.com/slavafomin/17ded0e723a7d3216fb3d8bf845c2f30.
И здесь я предоставляю копию кода:
матч-другой-validator.ts
import {FormControl} from '@angular/forms';
export function matchOtherValidator (otherControlName: string) {
let thisControl: FormControl;
let otherControl: FormControl;
return function matchOtherValidate (control: FormControl) {
if (!control.parent) {
return null;
}
// Initializing the validator.
if (!thisControl) {
thisControl = control;
otherControl = control.parent.get(otherControlName) as FormControl;
if (!otherControl) {
throw new Error('matchOtherValidator(): other control is not found in parent group');
}
otherControl.valueChanges.subscribe(() => {
thisControl.updateValueAndValidity();
});
}
if (!otherControl) {
return null;
}
if (otherControl.value !== thisControl.value) {
return {
matchOther: true
};
}
return null;
}
}
Использование
Здесь вы можете использовать его с реактивными формами:
private constructForm () {
this.form = this.formBuilder.group({
email: ['', [
Validators.required,
Validators.email
]],
password: ['', Validators.required],
repeatPassword: ['', [
Validators.required,
matchOtherValidator('password')
]]
});
}
Более свежие валидаторы можно найти здесь: moebius-mlm/ng-validators.
Ответ 3
найдено гораздо более простое решение. Не уверен, что это правильный способ сделать это, но он работает для меня.
<!-- PASSWORD -->
<ion-item [ngClass]="{'has-error': !signupForm.controls.password.valid && signupForm.controls.password.dirty}">
<ion-input formControlName="password" type="password" placeholder="{{ 'SIGNUP.PASSWORD' | translate }}" [(ngModel)]="registerCredentials.password"></ion-input>
</ion-item>
<!-- VERIFY PASSWORD -->
<ion-item [ngClass]="{'has-error': !signupForm.controls.verify.valid && signupForm.controls.verify.dirty}">
<ion-input formControlName="verify" [(ngModel)]="registerCredentials.verify" type="password" pattern="{{registerCredentials.password}}" placeholder="{{ 'SIGNUP.VERIFY' | translate }}"> </ion-input>
</ion-item>
См
pattern="{{registerCredentials.password}}"
Ответ 4
Angular 4.3.3 решение!
Вы можете сделать это, используя: [formGroup]
, formGroupName
, formControlName
в html и new FormGroup
, new FormControl
и пользовательский areEqual
метод в TS
reg.component.html
<div [formGroup]="userFormPassword">
<div>
<input formControlName="current_password" type="password" placeholder="Current Password">
</div>
<div formGroupName="passwords">
<input formControlName="new_password" type="password" placeholder="New Password">
</div>
<div formGroupName="passwords">
<input formControlName="repeat_new_password" type="password" class="form-control" placeholder="Repeat New Password">
<div class="input-error" *ngIf="
userFormPassword.controls['passwords'].errors &&
userFormPassword.controls['passwords'].errors.areEqual &&
userFormPassword.controls['passwords'].controls.repeat_new_password.touched &&
userFormPassword.controls['passwords'].controls.new_password.touched
">PASSWORDS do not match
</div>
</div>
</div>
reg.component.ts
export class HomeHeaderSettingsModalComponent implements OnInit {
userFormPassword: FormGroup;
// ...
static areEqual(c: AbstractControl): ValidationErrors | null {
const keys: string[] = Object.keys(c.value);
for (const i in keys) {
if (i !== '0' && c.value[ keys[ +i - 1 ] ] !== c.value[ keys[ i ] ]) {
return { areEqual: true };
}
}
}
ngOnInit() {
this.userFormPassword = new FormGroup({
'current_password': new FormControl(this.user.current_password, [
Validators.required,
]),
'passwords': new FormGroup({
'new_password': new FormControl(this.user.new_password, [
Validators.required
]),
'repeat_new_password': new FormControl(this.user.repeat_new_password, [
Validators.required
])
}, HomeHeaderSettingsModalComponent.areEqual)
});
}
}
Результат:
![result]()
Ответ 5
Если вы используете RC.5 и не можете найти ControlGroup, вы можете попробовать использовать FormGroup. Вы можете узнать больше из моего ответа:
Angular 2 Проверка формы RC.5 для повторения пароля
Ответ 6
Используя эту библиотеку ng2-validation-manager, вы можете легко сделать это:
this.form = new ValidationManager({
'password' : 'required|rangeLength:8,50',
'repassword' : 'required|equalTo:password'
});
Ответ 7
Кроме того, с angular 2 rc4 с формами 0.2.0 разметка и атрибут, вызывающий имя группы, используемое для включения сгруппированных входов, необходимы для предотвращения ошибок
<div formGroupName="passwords">group input fields here... </div>
Ответ 8
Ну, я искал ответ на эту тему, и все было слишком велико для моей лености, поэтому я сделал это так. Я думаю, что это хорошо работает.
Я использовал ngModel для привязки пароля и ввода repeatPassword, а затем я отобразили или спрятали div с сообщением сравнения паролей с [скрытый] атрибут в angular 2.
<label for="usr">Password</label>
<input placeholder="12345" id="password" type="text" class="form-control"
[(ngModel)]="password">
<label for="usr">Repeat pasword</label>
<input placeholder="12345" type="text" class="form-control"
[(ngModel)]="repeatPassword">
<div [hidden]="password == repeatPassword">Passwords do not match!</div>
Ответ 9
Сохраните пароль в переменной экземпляра.
password = new FormControl('', [Validators.required]);
Затем используйте его в своей группе форм.
this.registrationForm = this.fb.group({
'email': ['', [
Validators.required,
NGValidators.isEmail,
]
],
'password': this.password,
'password2': ['', [Validators.required, this.passwordMatch]]
});
Таким образом, функция выглядит следующим образом.
private passwordMatch() {
let that = this;
return (c: FormControl) =>
{
return (c.value == that.password.value) ? null : {'passwordMatch': {valid: false}};
}
}
Я знаю, что это не лучшее решение, но его работа!
Ответ 10
Здесь мой способ использования Angular Validators
КОМПОНЕНТ:
import { UserModel } from '../../settings/users/user.model';
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { FormRequestModel } from '../Shared/form.model';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-add-user',
templateUrl: './add-user.component.html',
styleUrls: ['./add-user.component.scss']
})
export class AddUserComponent implements OnInit {
passwordsForm: FormGroup;
user: UserModel;
constructor(private fb: FormBuilder) { }
ngOnInit() {
this.passwordsForm = this.fb.group({
inputPassword: ['', Validators.compose([Validators.required, Validators.minLength(6), Validators.maxLength(50)])],
inputPasswordAgain: ['']
});
}
}
HTML:
<form class="form-horizontal" [formGroup]="passwordsForm" novalidate>
<div class="form-group">
<br/>
<label for="inputPassword" class="col-sm-2 control-label">Password</label>
<div class="col-sm-10">
<input type="password" formControlName="inputPassword" class="form-control" id="inputPassword" placeholder="Password">
</div>
</div>
<div class="alert alert-danger" *ngIf="!passwordsForm.controls['inputPassword'].valid && passwordsForm.controls['inputPassword'].touched">Password must contain at least 6 characters!!</div>
<div class="form-group">
<br/>
<label for="inputPasswordAgain" class="col-sm-2 control-label">Password again</label>
<div class="col-sm-10">
<input type="password" formControlName="inputPasswordAgain" class="form-control" id="inputPasswordAgain" placeholder="Password again">
</div>
</div>
<!-- Show div warning element if both inputs does not match the validation rules below -->
<div class="alert alert-danger" *ngIf="passwordsForm.controls['inputPasswordAgain'].touched
&& passwordsForm.controls['inputPasswordAgain'].value !== passwordsForm.controls['inputPassword'].value">
Both passwords must be equal!</div>
Ответ 11
Я нашел решение, которое сделало меня счастливее, насколько совместимость кода с обработкой ошибок:
1st: создайте собственный класс проверки со статическим методом, который выполняет проверку
Этот метод должен иметь параметр AbstractControl, который angular вводит
Обратите внимание, что вы передадите это в элементе управления ConfirmPassword, поэтому вам нужно вызвать родителя, чтобы перейти в FormGroup. Оттуда вы вызываете formGroup.get('myControl') и получаете элементы управления для пароля и подтверждаете, как вы их назвали, когда вы создали группу форм.
import {AbstractControl} from '@angular/forms';
export class PasswordValidation {
static MatchPassword(AC: AbstractControl) {
const formGroup = AC.parent;
if (formGroup) {
const passwordControl = formGroup.get('Password'); // to get value in input tag
const confirmPasswordControl = formGroup.get('Confirm'); // to get value in input tag
if (passwordControl && confirmPasswordControl) {
const password = passwordControl.value;
const confirmPassword = confirmPasswordControl.value;
if (password !== confirmPassword) {
return { matchPassword: true };
} else {
return null;
}
}
}
return null;
}
}
2nd: используйте свой клиентский валидатор так же, как вы используете углы
this.registerForm = this.fb.group({ // <-- the parent FormGroup
Email: ['', Validators.required ],
Username: ['', Validators.required ],
FirstName: ['', Validators.required ],
Password: ['',
[
Validators.required,
Validators.minLength(6)
]
],
Confirm: ['',
[
Validators.required,
PasswordValidation.MatchPassword
]
]
});
Angular затем добавит "matchPassword": true для вашего подтверждения. Контролирует ошибки точно так же, как добавляет "required" true при отсутствии значения
Ответ 12
Мое решение для Angular 4.3.4, которое не требует дополнительного FormGroup
:
- зарегистрировать специальный валидатор для
repeatedPassword
, проверяя, являются ли пароли одинаковыми
- подписать обработчик на
password.valueChanges
во время создания формы и вызвать .updateValueAndValidity() method
on repeatedPassword
Вот какой код:
form: FormGroup
passwordFieldName = 'password'
repeatedPasswordFieldName = 'repeatedPassword'
createForm() {
this.form = this.formBuilder.group({
login: ['', [Validators.required, Validators.minLength(3), Validators.maxLength(255), Validators.email]],
[passwordFieldName]: ['', [Validators.required, Validators.minLength(6), Validators.maxLength(255)]],
[repeatedPasswordFieldName]: ['', [Validators.required, this.samePassword]]
});
this.form
.get(passwordFieldName)
.valueChanges.subscribe(() => {
this.form
.get(repeatedPasswordFieldName).updateValueAndValidity();
})
}
samePassword(control: FormControl) {
if (!control || !control.parent) {
return null;
}
if (control.value !== control.parent.get(passwordFieldName).value) {
return {'passwordMismatch': true}
}
return null;
}
Ответ 13
Я просто хочу опубликовать свое решение:
this.authorizationSettings = formBuilder.group({
currentPassword: [null, Validators.compose([Validators.required, Validators.minLength(8)])],
newPassword: [null, Validators.compose([Validators.required, Validators.minLength(8)])],
repeatNewPassword: [null]
});
this.authorizationSettings.controls.newPassword.valueChanges.subscribe(data => {
if (data) {
data = data.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
}
this.authorizationSettings.controls.repeatNewPassword
.clearValidators();
this.authorizationSettings.controls.repeatNewPassword
.setValidators(Validators.compose([Validators.required, Validators.pattern(data)]));
});
Сначала нам нужно создать группу форм, а затем подписать первое поле пароля и добавить подтверждение для повторного поля.
Ответ 14
Просто начиная с Angular, и я нашел это решение, не знаю, хорошо ли это:
// Custom password confirmation validation
static matchFieldValidator(fieldToMatch:string) : ValidatorFn {
return (control : AbstractControl) : { [key: string]: any;} => {
let confirmField = control.root.get(fieldToMatch);
return (confirmField && control.value !== confirmField.value) ? {match:false} : null;
}
}
Таким образом вы можете просто сделать что-то подобное при настройке правил проверки
this.registrationForm = fb.group({
...
password1 : ['', [Validators.minLength(3)]],
// remember to replace RegisterComponent with YOUR class name
password2 : ['', [RegisterComponent.matchFieldValidator('password1')]],
});
Ответ 15
Резюме
- Проверка триггера каждый раз, когда изменяется значение другого элемента управления.
- Отказаться от подписки, чтобы избежать утечек памяти.
- return
{match: true}
позволит нам проверить, имеет ли данный элемент управления ошибку с помощью myControl.hasError('match')
Реализация
import { AbstractControl, ValidatorFn } from '@angular/forms';
import { Subscription } from 'rxjs/Subscription';
export function matchOtherValidator(otherControlName: string): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } => {
const otherControl: AbstractControl = control.root.get(otherControlName);
if (otherControl) {
const subscription: Subscription = otherControl
.valueChanges
.subscribe(() => {
control.updateValueAndValidity();
subscription.unsubscribe();
});
}
return (otherControl && control.value !== otherControl.value) ? {match: true} : null;
};
}
Пример
this.registerForm = formBuilder.group({
email: ['', [
Validators.required, Validators.email
]],
password: ['', [
Validators.required, Validators.minLength(8)
]],
confirmPassword: ['', [
Validators.required, matchOtherValidator('password')
]]
});