Подтвердить что ты не робот

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

Любая идея? Спасибо.

4b9b3361

Ответ 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

Ответ 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')
            ]]
        });