Change ion-input type. Show/Hide password directive/component

Hi, I’m trying to implement a show/hide password similar to this one.

The problem I’m facing is that the TextInput directive from angular 2 has it’s type set method private so I can’t change the input type dynamically.

<show-hide-container>
    <ion-input type="password" placeholder="Password"></ion-input>
</show-hide-container>
export class ShowHideContainer
{
  show = false;

  @ContentChild(TextInput) ion_input: TextInput;

  constructor(){}

  toggleShow()
  {
    this.show = !this.show;
    if (this.show){
      // type is private!!!
      this.ion_input.type("text");
    }
    else {
      this.ion_input.type("password");
    }
  }
}

any help would be much appreciated!

1 Like

Hi!
Change your directive [show-hide-input] like this:

import { Directive, HostBinding, ElementRef } from '@angular/core';

@Directive({
    selector: '[show-hide-input]'
})
export class ShowHideInput {

    @HostBinding() type: string;

    constructor(private el: ElementRef) {
        this.type = 'password';
    }

    changeType(type: string) {  // in your case function name is type
        this.type = type;
        this.el.nativeElement.children[0].type = this.type; // change type for input inside the ion-input
    }

}

And in your template:

<show-hide-container>
    <ion-input type="password" placeholder="Password" show-hide-input></ion-input> // add the directive show-hide-input
</show-hide-container>

It works for me.

1 Like

Thank you so much!

At first I thought I could avoid using another directive (show-hide-input) and use the <ion-input> instead. But the methods I needed to access were private within the <ion-input> component, so it seems there’s no choice but to use the show-hide-input directive for this.

Another issue i found is that if you are using <ion-item> component along with <ion-input> you should put both of them inside the <show-hide-container>

THIS DOESN’T WORK

<ion-item>
  <show-hide-container>
    <ion-input type="password" placeholder="Password" formControlName="password" show-hide-input></ion-input>
  </show-hide-container>
</ion-item>

THIS WORKS

<show-hide-container>
  <ion-item>
    <ion-input type="password" placeholder="Password" formControlName="password" show-hide-input></ion-input>
  </ion-item>
</show-hide-container>

Having said that, it would be awesome if the guys from the ionic team could write a post or guide about the proper way to extend and create custom directives for the ionic framework. I believe there are tons of developers like me that want to crete awesome stuff with ionic and at the end these custom directives and UI/UX widgets will be super useful for the community.

The community is what makes ionic great.

1 Like

There is no need to do all that is written above, just do this

in .html

 <ion-item>
    <ion-label fixed>Password</ion-label>
    <ion-input #input type="password" [(ngModel)]="loginUtente.password"></ion-input>
  </ion-item>

<ion-item>
    <ion-label for="checkbox" *ngIf="!passwordCheckbox">show password</ion-label>
    <ion-label for="checkbox" *ngIf="passwordCheckbox">hide password</ion-label>
    <ion-checkbox  class="marginTop" id="checkbox" style="border-style: none;" [(ngModel)]="passwordCheckbox" (click)="showPassword(input)"></ion-checkbox>
  </ion-item>

in .ts

showPassword(input: any): any {
   input.type = input.type === 'password' ?  'text' : 'password';
  }

I hope to have helped

3 Likes

I would much prefer binding [type] instead of directly fooling with DOM attributes in showPassword() (which should rather be named toggleShowPassword() or something to indicate that it doesn’t just show the password).

Using the approach of the OP’s accepted solution in the latest Ionic 2 version I get the following error:

Unhandled Promise rejection: Template parse errors:
Can’t bind to ‘type’ since it isn’t a known property of ‘ion-input’.

I created two separate .ts files for both the container and input attribute directive & imported them into the declarations of app.module.ts.

Does anyone know to resolve this? Thanks!

Hi thorgalle, this is another simple solution. I hope helped.

login.html

<ion-item>
        <ion-input [type]="getType()"></ion-input>
        <ion-icon name="eye" item-right (click)="toggleTextPassword()"></ion-icon>
 </ion-item>

login.ts

export class LoginPage {
  isActiveToggleTextPassword: Boolean = true;
  public toggleTextPassword(): void{
      this.isActiveToggleTextPassword = (this.isActiveToggleTextPassword==true)?false:true;
  }
  public getType() {
      return this.isActiveToggleTextPassword ? 'password' : 'text';
  }
}
6 Likes

I don’t know why this would be better then this:

HTML

<ion-input [type]="password_type" placeholder="Password" name="password" [(ngModel)]="password" required></ion-input>
<ion-icon name="eye" item-right (click)="togglePasswordMode()"></ion-icon>

TS

password_type: string = 'password';

togglePasswordMode() {   
   this.password_type = this.password_type === 'text' ? 'password' : 'text';
}
10 Likes

I am also getting this issue. I thought it was related to lazy loading but maybe it is the ionic version?

1 Like

This was a easy, 100% effective solution.
minor change on my end

togglePasswordMode() {   
   this.password_type === 'text' ? 'password' : 'text';
}

Not sure why you had the extra this.password_type =
Typo or just a personal preference for doing things?

2 Likes

Typo :slight_smile: thanks

No problem. Thanks for the pragmatic solution

1 Like

Hey! I am getting errors with this. Error: Template parse errors: Can't bind to 'type' since it isn't a known property of 'ion-input'.

I recently updated to Ionic4. Is that the reason? Any update

Sorry I figured it out… Change the @HostBinding to @Input

Simple and neat solution. Thank you

simple, not complicated and effective solution… thank you!

HTML

<ion-label position="floating">Password</ion-label>
<ion-input [type]="hide ? 'password' : 'text'" required></ion-input>
<ion-icon slot="end" [name]="hide ? 'eye' : 'eye-off'" (click)="hide = !hide"></ion-icon>

TS

import { Component, OnInit } from '@angular/core';

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

  hide = true;

  constructor() { }

  ngOnInit() {}

}

I think that the easiest way to change the value of the attributes is with an if and a boolean, by clicking on the eye icon, for example

3 Likes

Thanks! This was so clean and easy to implement :slight_smile:

simple, short and clean solution

simple, short and clean solution