1
votes

I was trying to create a password reset form where I needed to create two fields for a new password and confirming the new password. I was testing whether they are same or not using custom validation in angular2, but my code is not working. I am attaching my component file and custom validation class here, can anyone please suggest me what can be the proper solution to it.

I am using angular 2.4

Component Code:

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators} from '@angular/forms';
import { Checkpassword } from '../checkpassword';

@Component({
  selector: 'app-contact-form',
  templateUrl: './contact-form.component.html',
  styleUrls: ['./contact-form.component.css']
})
export class ContactFormComponent implements OnInit {

  signUpForm: FormGroup;
  constructor(fb: FormBuilder) {
      this.signUpForm = fb.group({
          oldpassword: ['', Validators.compose([
            Validators.required,
            Checkpassword.checkPasswordLength
          ])],
          newpassword1: ['', Validators.required],
          newpassword2: ['', Validators.required]
      }, {validator: Checkpassword.isSamePassword});
  }

  ngOnInit() {
  }

}

Custom Validator Code:

import { FormControl, FormGroup } from '@angular/forms'

export class Checkpassword {
    static checkPasswordLength(control: FormControl){
        if(control.value.length > 0 && control.value.length < 5 ) return {smallPassword: true};
        return null;
    }

    static isSamePassword(group: FormGroup){
        let newpassword1 = group.controls['newpassword1'].value;
        let newpassword2 = group.controls['newpassword2'].value;

        if(newpassword1 !== newpassword2){
            return {notSamePassword: true};
        }


        return null;
    }
}
4
any errors you are getting? - Aravind
no errors @Aravind - habibalsaki

4 Answers

8
votes

If you're using ngModel you can just use pattern and reference the password already entered.

pattern={{user[0].password}}

Full code:

    <label>Password:</label>
    <input type="text" name="password" #password="ngModel" minlength="6" required [(ngModel)]="user[0].password">
    <div *ngIf="password.errors && (password.dirty || password.touched)"class="alert-error">
      <div [hidden]="!email.errors.required">
        Password is required!
      </div>
      <div [hidden]="!email.errors.minlength">
        Password must be at least 6 characters or longer.
      </div>
    </div>
    <br>
  <label>Confirm password:</label>
    <input type="text" name="repassword" #repassword="ngModel" minlength="6" pattern={{user[0].password}} required [(ngModel)]="user[0].repassword">
    <div *ngIf="repassword.errors && (repassword.dirty || repassword.touched)" class="alert-error">
      <div [hidden]="!repassword.errors.required">
        Please confirm the password.
      </div>
      <div [hidden]="!repassword.errors.minlength">
        Password must be at least 6 characters or longer.
      </div>
      <div [hidden]="!repassword.errors.pattern">
        Passwords must match.
1
votes

Your validator function takes a group as an argument, but you are assigning only the validator to only one control so. To fix your problem, you should use it in the same component and pass two arguments as below

@Component({
  selector: 'app-contact-form',
  templateUrl: './contact-form.component.html',
  styleUrls: ['./contact-form.component.css']
})
export class ContactFormComponent implements OnInit {

  signUpForm: FormGroup;
  constructor(fb: FormBuilder) {
      this.signUpForm = fb.group({
          oldpassword: ['', Validators.compose([
            Validators.required,
            Checkpassword.checkPasswordLength
          ])],
          newpassword1: ['', Validators.required],
          newpassword2: ['', Validators.required]
  //////////////////////////////////////////////////////////////////////////
      }, {validator: this.isSamePassword(newpassword1,newpassword2});
 //////////////////////////////////////////////////////////////////////////
  }

  ngOnInit() {
  }
 //////////////////////////////////////////////////////////////////////////
private isSamePassword(newpassword1 : FormControl, newpassword1 : FormControl):{[key: string]:any}{

    if(newpassword1 !== newpassword2){
        return {'notSamePassword': true};
    }
    return null;
}
 //////////////////////////////////////////////////////////////////////////
}

Note: The return type of the function and notSamePassword should be enclosed with in quotes

0
votes

app.module.ts

Add these into your app.module.ts file to use reactive forms

import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { FormsModule, ReactiveFormsModule } from '@angular/forms';
    import { AppComponent } from './app.component';
    @NgModule({
      imports: [
        BrowserModule,
        FormsModule,
        ReactiveFormsModule,
     ],
    declarations: [
    AppComponent
     ]
  providers: [],
  bootstrap: [
    AppComponent
   ]
  })
export class AppModule {}

app.component.ts

import { Component,OnInit } from '@angular/core';
import template from './add.component.html';
import { FormGroup,FormBuilder,Validators } from '@angular/forms';
import { matchingPasswords } from './validators';
@Component({
    selector: 'app',
    template
})
export class AppComponent implements OnInit {
    addForm: FormGroup;
    constructor(private formBuilder: FormBuilder) {
    }
    ngOnInit() {

    this.addForm = this.formBuilder.group({
            username: ['', Validators.required],
            email: ['', Validators.required],
            role: ['', Validators.required],
            password: ['', Validators.required],
            password2: ['', Validators.required] }, 
          { validator: matchingPasswords('password', 'password2') 
        })
    };

addUser() {
        if (this.addForm.valid) {
            var adduser = {
                username: this.addForm.controls['username'].value,
                email: this.addForm.controls['email'].value,
                password: this.addForm.controls['password'].value,
                profile: {
                    role: this.addForm.controls['role'].value,
                    name: this.addForm.controls['username'].value,
                    email: this.addForm.controls['email'].value
                }
            };
          console.log(adduser);// adduser var contains all our form values. store it where you want 
            this.addForm.reset();// this will reset our form values to null 
        }
    }  
}

app.component.html

<div>
  <form [formGroup]="addForm">
   <input type="text" placeholder="Enter username" formControlName="username" />
   <input type="text" placeholder="Enter Email Address" formControlName="email"/>
   <input type="password" placeholder="Enter Password" formControlName="password" />
   <input type="password" placeholder="Confirm Password" name="password2" formControlName="password2"/>
   <div class='error' *ngIf="addForm.controls.password2.touched">
    <div *ngIf="addForm.hasError('mismatchedPasswords')">                                  Passwords do not match
  </div>
</div>
<select name="Role" formControlName="role">
    <option value="admin" >Admin</option>
    <option value="Accounts">Accounts</option>
    <option value="guest">Guest</option>
</select>
<br/>
<br/>
<button type="submit" (click)="addUser()"> Add User </button>
</form>
</div>

validators.ts

export function matchingPasswords(passwordKey: string, confirmPasswordKey: string) {
    return (group: ControlGroup): {
        [key: string]: any
    } => {
        let password = group.controls[passwordKey];
        let confirmPassword = group.controls[confirmPasswordKey];

        if (password.value !== confirmPassword.value) {
            return {
                mismatchedPasswords: true
            };
        }
    }
}
0
votes

After trying much and taking help from various blog posts: I found the solution

New Component file

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators} from '@angular/forms';
import { Checkpassword } from '../checkpassword';

@Component({
  selector: 'app-contact-form',
  templateUrl: './contact-form.component.html',
  styleUrls: ['./contact-form.component.css']
})
export class ContactFormComponent implements OnInit {

  signUpForm: FormGroup;
  constructor(fb: FormBuilder) {
      this.signUpForm = fb.group({
          oldpassword: ['', Validators.compose([
            Validators.required,
            Checkpassword.checkPasswordLength
          ])],
          passwords: fb.group({
            newpassword1: ['', Validators.required],
            newpassword2: ['', Validators.required]
          },{validator: Checkpassword.isSamePassword})    
      });
  }

  ngOnInit() {
  }

  onSubmit(){
    console.dir(this.signUpForm.controls);
  }

}

Validator File:

import { FormControl, FormGroup } from '@angular/forms'

export class Checkpassword {
    static checkPasswordLength(control: FormControl){
        if(control.value.length > 0 && control.value.length < 5 ) return {smallPassword: true};
        return null;
    }

    static isSamePassword(group: FormGroup){
        let newpassword1 = group.controls['newpassword1'].value;
        let newpassword2 = group.controls['newpassword2'].value;

        if(newpassword1 !== newpassword2){
            return {notSamePassword: true};
        } 
       // console.dir(group.controls);

        return null;
    }
}

HTML file

<div class="container">
    <form [formGroup]="signUpForm" (ngSubmit)="onSubmit()">
        <div class="form-group">
            <label for="oldpassword">Old Password</label>
            <input type="password" 
                name="oldpassword" formControlName="oldpassword"
                class="form-control" 
                id="oldpassword">
        </div>
        <div *ngIf="signUpForm.controls.oldpassword.touched && !signUpForm.controls.oldpassword.valid"> 
            <div class="alert alert-danger" *ngIf="signUpForm.controls.oldpassword.errors.smallPassword">
                Old Password is too small
            </div>
            <div class="alert alert-danger" *ngIf="signUpForm.controls.oldpassword.errors.required">
                Old Password is required
            </div>
        </div>

        <div formGroupName="passwords">
            <div class="form-group">
                <label for="newpassword1">New Password</label>
                <input type="password" 
                    name="newpassword1" formControlName="newpassword1"

                    class="form-control" 
                    id="newpassword1">
            </div>
            <div *ngIf="signUpForm.controls.passwords?.controls.newpassword1?.touched 
                && !signUpForm.controls.passwords?.controls.newpassword1?.valid" 
                class="alert alert-danger">New Password is required</div>

            <div class="form-group">
                <label for="newpassword2">Confirm New Password</label>
                <input type="password" 
                    name="newpassword2" formControlName="newpassword2"

                    class="form-control" 
                    id="newpassword2">
            </div>

            <div *ngIf="signUpForm.controls.passwords?.controls.newpassword2?.touched 
                && !signUpForm.controls.passwords?.controls.newpassword2?.valid">
                <div class="alert alert-danger">
                    Confirm password is required
                </div>

            </div>  

            <div class="alert alert-danger" 
                *ngIf="signUpForm.get('passwords').hasError('notSamePassword')">
                Passwords do not match
            </div>  
        </div>
        <button class="btn btn-primary" type="submit">Change Password</button>
    </form>
</div>