Ionic 4 Input Password con botón para mostrar/ocultar texto

Ionic 4 Input Password con botón para mostrar/ocultar texto

En un formulario muchas veces se necesita agregar la funcionalidad para mirar u ocultar la contraseña que se esta ingresando.

Con Ionic tuve la necesidad de implementarlo y luego de buscar en muchos foros los cuales me ayudaron a lograrlo en un 75%, debido a que no agregaban la funcionalidad de que al apretar el icono para mostrar u ocultar la contraseña mientras escribía se escondía el teclado y eso no me gustaba, por lo que me gustaría compartir la solución que encontré para este problema.

En el HTML debemos agregar un botton que se posicione al final del ion-item que uso en este caso y dentro de este agregamos el icono del ojo que como queremos que cambie y muestre u oculte el icono lo pasamos como un atributo dinamico encerrado entre [ ].

Ahora en el boton le adjuntamos el evento "click" para cambiar el modo o tipo de input que se usa haciendolo dinamico ademas de en el input agregarle el id por medio del simbolo #.

Versión 1

HTML

<ion-item>
    <ion-label  position="floating">Contraseña</ion-label>
    <ion-input  #passwordEyeRegister  [type]="passwordTypeInput"  formControlName="password"></ion-input>
    <button  item-end  class="btn_eye_icon"  (click)="togglePasswordMode()">
        <ion-icon  [name]="iconpassword"></ion-icon>
    </button>
</ion-item>

Ahora en el archivo Typescript debemos hacer lo que se puede observar en los comentarios

TypeScript

import { Component, OnInit, ViewChild} from  '@angular/core';
// Importar el ViewChild para acceder a un elemento del DOM

@ViewChild('passwordEyeRegister') passwordEye;
// Seleccionamos el elemento con el nombre que le pusimos con el #
passwordTypeInput  =  'password';
// Variable para cambiar dinamicamente el tipo de Input que por defecto sera 'password'
iconpassword  =  'eye-off';

// Esta función verifica si el tipo de campo es texto lo cambia a password y viceversa, además verificara el icono si es 'eye-off' lo cambiara a 'eye' y viceversa
togglePasswordMode() {
    this.passwordTypeInput  =  this.passwordTypeInput  ===  'text'  ?  'password'  :  'text';
    this.iconpassword  =  this.iconpassword  ===  'eye-off'  ?  'eye'  :  'eye-off';
    this.passwordEye.el.setFocus();
}

Finalmente le damos algunos estilos para que el botón se pueda observar de una forma decente y no interfiera con el label o el mismo input además de ocultar que al apretar el botón aparezca un borde en el evento focus

SCSS

.btn_eye_icon{
    position: absolute;
    right: 0;
    bottom: 4px;
    background: transparent;
    ion-icon{
        font-size: 22px;
        color:#757575;
    }
}

.btn_eye_icon:focus{
    outline: none  !important;
}

Versión 2 (Actualización)

Para ofrecer una mejor interactividad se debe hacer de la siguiente manera:

HTML

<ion-item lines="none">
    <ion-label  position="stacked">Contraseña</ion-label>
    <ion-input  #passwordEyeRegister  [type]="passwordTypeInput"  formControlName="password" clearOnEdit="false"> 
        </ion-input>
    <button  item-end  class="btn_eye_icon"  (click)="togglePasswordMode()">
        <ion-icon  [name]="(passwordTypeInput === 'text')?'eye-off':'eye'"></ion-icon>
    </button>
</ion-item>

TS

import { Component, OnInit, ViewChild, ElementRef} from  '@angular/core';
// Importar el ViewChild para acceder a un elemento del DOM

@ViewChild('passwordEyeRegister, { read: ElementRef }) passwordEye: ElementRef;
// Seleccionamos el elemento con el nombre que le pusimos con el #
passwordTypeInput  =  'password';
// Variable para cambiar dinamicamente el tipo de Input que por defecto sera 'password'

// Esta función verifica si el tipo de campo es texto lo cambia a password y viceversa, además verificara el icono si es 'eye-off' lo cambiara a 'eye' y viceversa
togglePasswordMode() {
         //cambiar tipo input
     this.passwordTypeInput = this.passwordTypeInput === 'text' ? 'password' : 'text';
        //obtener el input
        const nativeEl = this.passwordEye.nativeElement.querySelector('input');
        //obtener el indice de la posición del texto actual en el input
        const inputSelection = nativeEl.selectionStart;
        //ejecuto el focus al input
        nativeEl.focus();
       //espero un milisegundo y actualizo la posición del indice del texto
        setTimeout(() => {
            nativeEl.setSelectionRange(inputSelection, inputSelection);
        }, 1);

}

Dándonos como resultado una interfaz similar a la de la imagen

GIF-190705_225852.gif