Show hide password with verification

I had the password input working perfectly until I added the verification. Now the input only becomes active when the password is toggled to visible.

Please advise. I am still learning.

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

@Component({
    selector: 'app-login',
    templateUrl: './login.page.html',
    styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {
    login: FormGroup;
    showPassword: boolean;
    showPin: boolean;
    showConfirm: boolean;

    // countries;


    constructor(private fb: FormBuilder) {

        this.login = this.fb.group({


            password: new FormControl('', Validators.compose([
                Validators.required,
                Validators.minLength(8),
                Validators.maxLength(20),
                Validators.pattern('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&].{8,}$')
            ])),
            email: new FormControl('', Validators.compose([
                Validators.required,
                Validators.minLength(6),
                Validators.maxLength(20),
                Validators.pattern('^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$')
            ])),
        });
    }

    formSubmit(login) {
        console.log('test: ', login);
    }


    togglePasswordText() {
        this.showPassword = !this.showPassword;
    }
    toggleConfirmText() {
        this.showConfirm = !this.showConfirm;
    }

    ngOnInit() {
    }


}


And the html

    <div class="color-top">
        <div class="logo-top"><img src="assets/bb-logo-400.png" /></div>
    </div>
    <div class="spacer"></div>
    <h4 class="ion-text-center">Welcome back</h4>
    <!-- <p class="info-text ion-text-center ion-no-padding">Enter the 4 digit pin you received in your email</p> -->
    <ion-list>
        <form [formGroup]="login" (ngSubmit)="formSubmit(login)">
            <!-- email -->
            <ion-item>
                <p *ngIf="login.controls.email.invalid && login.controls.email.dirty" class="alert-msg">
                    You need to enter a valid email
                </p>
                <ion-label position="floating">Email</ion-label>
                <ion-input formControlName="email" name="email" type="email"></ion-input>
            </ion-item>

            <!-- password -->
            <ion-item *ngIf="showPassword">
                <p *ngIf="login.controls.password.invalid && login.controls.password.dirty" class="alert-msg">
                    Your password is incorrect. Please try again.
                </p>
                <ion-label position="floating">Password</ion-label>
                <ion-input type="text" *ngIf="!showPasswordText" formControlName="password"></ion-input>
                <ion-icon slot="end" color="primary" name="eye" (click)="togglePasswordText()"></ion-icon>
            </ion-item>
            <ion-item *ngIf="!showPassword">
                <ion-label position="floating">Password</ion-label>
                <ion-input type="password" *ngIf="!showPasswordText" formControlName="password"></ion-input>
                <ion-icon slot="end" color="medium" name="eye-off" (click)="togglePasswordText()"></ion-icon>
            </ion-item>
        </form>
    </ion-list>
    <ion-button expand="full" shape="round" color="primary" type="submit" [disabled]="!login.valid">
        Login</ion-button>
    <div class="form-info-text ion-text-center">
        <p><a>Reset password</a></p>
    </div>
</ion-content>
type or paste code here

Write your code in this way it has same validators but call method is different , this wont create any issue with your visible and not visible password feature as well Just do remember to type password according to the validation. let me know if you have any doubt regarding the code.
I used ng-containers for better error message calls and put all my error messages in array and call themaccordingly.

In Html

<ion-content class="ion-padding">
  <form class="form" [formGroup]="validations_form"  (ngSubmit)="formSubmit(validations_form.value)">
 
    <ion-item>
      <ion-label  position="floating" color="primary">Email</ion-label>
      <ion-input type="text" formControlName="email"></ion-input>
    </ion-item>
    <div class="validation-errors">
      <ng-container *ngFor="let validation of validation_messages.email">
        <div class="error-message" *ngIf="validations_form.get('email').hasError(validation.type) && (validations_form.get('email').dirty || validations_form.get('email').touched)">
          {{ validation.message }}
        </div>
      </ng-container>
    </div>
 <!--  Password -->
    <ion-item *ngIf="showpassword">
      <ion-label  position="floating" color="primary">Password</ion-label>
      <ion-icon slot="end" color="primary" name="eye" (click)="togglePasswordText()"></ion-icon>
      <ion-input type="text" formControlName="password" class="form-controll" required></ion-input>
    </ion-item>
    <ion-item *ngIf="!showpassword">
      <ion-label  position="floating" color="primary">Password</ion-label>
      <ion-input type="password" formControlName="password" class="form-controll" required></ion-input>
      <ion-icon slot="end" color="medium" name="eye-off" (click)="togglePasswordText()"></ion-icon>
    </ion-item>
    <div class="validation-errors">
      <ng-container *ngFor="let validation of validation_messages.password">
        <div class="error-message" *ngIf="validations_form.get('password').hasError(validation.type) && (validations_form.get('password').dirty || validations_form.get('password').touched)">
          {{ validation.message }}
        </div>
      </ng-container>
    </div>
 
    <ion-button  class="submit-btn" type="submit"  [disabled]="!validations_form.valid">Log In</ion-button>
 
    <label class="error-message">{{errorMessage}}</label>
  </form>
<ion-content>

Inside your .ts file

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

validations_form: FormGroup;
  errorMessage: string = '';
  loading: any;
  public showpassword: boolean;

constructor(private formBuilder: FormBuilder) {  }

ngOnInit() {

   this.validations_form = this.formBuilder.group({
      email: new FormControl('', Validators.compose([
        Validators.required,
        Validators.minLength(6),
        Validators.maxLength(20),
        Validators.pattern('^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$') // example : test@gmail.com
      ])),
      password: new FormControl('', Validators.compose([
        Validators.minLength(8),
        Validators.maxLength(20),
        Validators.required,
        Validators.pattern('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&].{8,}$') 
//example:- Test@123 (it will take one capital letter, one special char , one numeric digit then only it will allow to submit)
      ])),
    });
  }

  togglePasswordText() {
    this.showpassword = !this.showpassword;
}
 
 validation_messages = {
    'email': [
      { type: 'required', message: 'Email is required.' },
      { type: 'pattern', message: 'Please enter a valid email.' }
    ],
    'password': [
      { type: 'required', message: 'Password is required.' },
      { type: 'minlength', message: 'Password must be at least 8 characters long. with one capital letter, one special char , one numeric digit ' }
    ]
  };

Thank you very much. I will implement this.

Your welcome, Happy to help :slight_smile: if u feel this solved your problem do mark it as solution.
Thanks

Unfortunately this is not working either.

what is the error it is showing ? with the code i gave , because i tried the code on my end and it works as intended. i have made a stackblitz for the above code working with validation. also dont forget to add ReactiveFormsModule in ur loginpage module

in the stackblitcz code i didnt put the showpassword function on ion-icon idk why but stackblitz wont recognize ion-icon so i made a button to use that function

Your code was perfectly fine. The problem was with the password swapping. It was undefined. Below is the fix to that problem. The ng-container was something i did not know about so I learnt something valuable. Thank you for your help.

export class LoginPage implements OnInit {

    login: FormGroup;
    showPassword = false;
    errorMessage = '';
    loading: any;
1 Like

awesome, glad i could help . do mark the a accepted answer for anyone coming here in future. Cheers :slight_smile:

Here is the working code. I did not make use of everything. This is working. The password validation will be on submit as this is a login, not registration.

html

<ion-content>
    <div class="color-top">
        <div class="logo-top"><img src="assets/bb-logo-400.png" /></div>
    </div>
    <div class="spacer"></div>
    <h4 class="ion-text-center">Welcome back</h4>
    <ion-list>
        <form class="form" [formGroup]="login" (ngSubmit)="formSubmit(login.value)">

            <ion-item>
                <ng-container>
                    <p *ngIf="login.controls.email.invalid && login.controls.email.dirty" class="alert-msg">
                        You need to enter a valid email
                    </p>
                </ng-container>
                <ion-label position="floating" color="primary">Email</ion-label>
                <ion-input type="text" formControlName="email"></ion-input>
            </ion-item>
            <!--  Password -->
            <ion-item *ngIf="showPassword">
                <ion-label position="floating" color="primary">Password</ion-label>
                <ion-icon slot="end" color="primary" name="eye" (click)="togglePasswordText()"></ion-icon>
                <ion-input type="text" formControlName="password" required></ion-input>
            </ion-item>

            <ion-item *ngIf="!showPassword">

                <ion-label position="floating" color="primary">Password</ion-label>
                <ion-input type="password" formControlName="password" required></ion-input>
                <ion-icon slot="end" color="medium" name="eye-off" (click)="togglePasswordText()"></ion-icon>
            </ion-item>

            <ion-button style="margin-top:30px;" expand="full" shape="round" color="primary" type="submit" [disabled]="!login.valid">Log In</ion-button>

        </form>
    </ion-list>
    <ion-content>

The typescript

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

@Component({
    selector: 'app-login',
    templateUrl: './login.page.html',
    styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {

    login: FormGroup;
    showPassword = false;
    errorMessage = '';
    loading: any;

    // countries;


    constructor(private fb: FormBuilder) {

        this.login = this.fb.group({
            email: new FormControl('', Validators.compose([
                Validators.required,
                Validators.minLength(6),
                Validators.maxLength(20),
                Validators.pattern('^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$')
            ])),
            password: new FormControl('', Validators.compose([
                Validators.required,
                Validators.minLength(8),
                // Validators.maxLength(20),
                // Validators.pattern('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&].{8,}$')
            ])),
        });
    }


    ngOnInit() {

    }


    formSubmit(login) {
        console.log('test: ', login);
    }


    togglePasswordText() {
        console.log('togglePasswordText: ', this.showPassword);

        this.showPassword = !this.showPassword;
    }

}

Sass

ion-header {
    --border-width: 0 0 0;
    ion-toolbar {
        --border-width: 0 0 0;
        overflow: visible;
        h2 {
            font-size: 1rem;
        }
    }
}

ion-content {
    .color-top {
        position: relative;
        display: block;
        width: 100%;
        height: 25vh;
        background: var(--ion-color-primary);
        .logo-top {
            position: absolute;
            z-index: 1000;
            left: 50%;
            transform: translate(-50%, 25%);
            img {
                width: 40vw;
            }
        }
    }
    .spacer {
        display: block;
        height: 8vh;
    }
    h4 {
        color: var(--ion-color-primary);
        padding-top: 8px;
    }
    .info-text {
        margin-top: 0;
        margin-bottom: 20px !important;
    }
    ion-list {
        margin-bottom: 20px;
        .form-title {
            text-align: left;
            color: var(--ion-color-primary);
            font-weight: 600;
            font-size: 1rem;
            margin-left: 16px;
            margin-bottom: 0;
            margin-top: 30px;
            .form-title-note {
                font-size: 0.9rem;
                font-style: italic;
                font-weight: normal;
                color: var(--ion-color-dark)
            }
        }
        ion-item-divider {
            ion-label {
                text-transform: uppercase;
            }
        }
        ion-item {
            --border-color: var(--ion-inactive-on-red);
            ion-label {
                margin-left: 0px;
                text-transform: uppercase;
                color: var(--ion-color-primary);
                font-size: 0.8rem;
            }
            ion-input {
                --font-size: 1rem;
                --color: var(--ion-color-dark);
                margin-bottom: 10px;
            }
            ion-row {
                margin-top: 20px;
                padding-bottom: 5px;
                ion-input {
                    --placeholder-color: var(--ion-color-primary);
                    --placeholder-opacity: 0.4;
                }
            }
            ion-icon {
                font-size: 2rem;
                margin-top: 27px;
            }
        }
    }
    ion-button {
        margin-left: 20vw;
        margin-right: 20vw;
    }
}

// Form error message
.alert-msg {
    position: absolute;
    left: 0;
    right: 0;
    width: 100%;
    font-size: 0.8rem;
    text-align: center;
    color: var(--ion-color-primary-shade);
    font-weight: 400;
    padding: 10px;
    margin-left: auto;
    margin-top: 50px;
    margin-right: auto;
    border-radius: 5px;
    padding-top: 3px;
    padding-bottom: 0;
    margin-bottom: 0;
    height: 17px;
}
1 Like