Wrap ion-input for a custom Reactive Form component

Hi all,

I’m using ionic 4 and I’d like to build a reusable form component. Probably it’s easy but my lack of knowledge is not helping me find the best way to achieve it.

Say I have a password input, with a toggle icon to show/hide the password. This could appear in at least 3 places: login, register and reset pages.

So one of these forms could be something like:

<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
    <ion-item>
        <ion-label position="floating">Email</ion-label>
        <ion-input name="email" type="email" formControlName="email"></ion-input>
    </ion-item>
    <app-password-item [form]="loginForm" formControlName="password"></app-password-item>
    <ion-button type="submit" [disabled]="loginForm.invalid" expand="block">Sign in!
    </ion-button>
</form>

...
    ngOnInit() {
        this.loginForm = this.formBuilder.group({
            email: ['', [Validators.required, Validators.email]],
            password: ['', [Validators.required]]
        });
    }
...

And my <app-password-item> would be

<ion-item>
    <ion-label position="floating">Password</ion-label>
    <ion-input name="password" [type]="passwordType" clearOnEdit="false"></ion-input>
    <ion-icon [name]="passwordIcon" class="password-icon" (click)='hideShowPassword()' slot="end"></ion-icon>
</ion-item>

And the corresponding typescript file:

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

@Component({
    selector: 'app-password-item',
    templateUrl: './password-item.component.html',
    styleUrls: ['./password-item.component.scss']
})
export class PasswordItemComponent implements OnInit {
    @Input() form: FormGroup;
    passwordType = 'password';
    passwordIcon = 'eye-off';

    constructor() {}

    ngOnInit() {}

    hideShowPassword() {
        this.passwordType = this.passwordType === 'text' ? 'password' : 'text';
        this.passwordIcon = this.passwordIcon === 'eye' ? 'eye-off' : 'eye';
    }
}

I’ve not put any css and other cosmetics to be short.

Now, I read about ControlValueAccessor, but I don’t understand if it’s the right choice, since I don’t want to create a custom control, but just wrap an existing one so that I can reuse it without copy/paste abuse.

I’m not asking about importing/exporting issues, I’m able to use it, but a way to let the custom component behave as the wrapped one, so that form validation works as if it was a simple <ion-input>.

I’m sorry if this has been asked before, but I didn’t find any similar post… Any suggestion is much appreciated!

Thank you all, ciao,
Fabio

Hi @ffalcinelli,

This may sound backwards and I’ve never done it myself but, have you tried getting a reference to the ion-input with @ViewChild() so you can access this property from a parent component?

Reimplementing a ControlValueAccessor sounds like a ton of work for something you already have… Maybe this option is worth exploring.

Let me know if you try!

Best,
Rodrigo

1 Like

Hello,

my english is not very good, so I understood you maybe wrong.
If you use a standard input then there is no need of a ControlValueAccesor. I personal prefer standard input with additional styling, to get rid of side effects.

https://angular.io/guide/reactive-forms

If you create a input like here shown as a rating component, https://alligator.io/angular/custom-form-control/
then you need ControllValueAccesor to make the concetion between rating component and angular side, that it knows how to do it.

Best regards, anna-liebt

1 Like

Hi! First of all thank you both for the answers!

Indeed seems like I can’t escape from ControlValueAccessor, the form builder complains…

Using ViewChild I don’t find a way to delegate ControlValueAccessor methods to the ElementRef.

Anna, what kind of drawbacks you’ve experienced? I’m moving my first steps so I’m prone to pitfalls! Thanks!

Edit: I changed the post since I was fooling myself, actually the code was not working :frowning:

1 Like