1

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;
    }
}
2
  • any errors you are getting? Commented Mar 18, 2017 at 20:56
  • no errors @Aravind Commented Mar 19, 2017 at 13:30

4 Answers 4

8

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.
Sign up to request clarification or add additional context in comments.

2 Comments

I was looking for an answer for model driven forms in angular, yours one is template driven, thanks though for your answer
I absolutely think that's the best answer for a Template-driven form! +1 angular.io/api/forms/PatternValidator
1

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

3 Comments

Well I found that quotes are not necessary as well as the return type of function. Also, I want to write the validation logic in different class.
so is this helpful or you need more help?
It helped me to search more to find out the solution I wanted, but it is not certainly what I looked for. Thanks for your assistance.
0

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

2 Comments

doesn't it look exactly as below expect the variable names? and are you sure that this will work?
@Aravind it is working for me.did you find anything wrong in my code ? let me know if you find anything wrong in it :) . i just want to provide complete answer with *ngIf="addForm.hasError('mismatchedPasswords') for showing error also. it will help other also :)
0

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.