Mask Number Field

Hey there,

If you’re still looking for a solution, check this out: https://github.com/ihadeed/ionic2-input-mask

Just installed it on my Ionic 2 Application and it worked well, only problem is when the guide option is on and you’re using a floating label. I might find a solution for that later (conditional guide), but it might require more modifications to the original library.

1 Like

Any luck with the text-mask-addons getting to work? Looking at the d.ts files all are exporting foo.

Hey there

The original text-mask now supports Ionic 2. There is no need to use my
fork anymore.

Checkout text-mask/text-mask on github

Have you been able to use the text-mask/text-mask?
I added to my Ionic 2 RC1 project but when I run ionic serve i get following error -

bundle failed: ‘textMaskModule’ is not exported by node_modules\angular2-text-mask\dist\angular2TextMask.js
(imported by src\app\app.module.ts)

Can you please let me know how to fix this?

1 Like

Hi @efbarbosa: can you give some example on how you achieve this?

Thanks,
Punleu

A few updates to custom directive

1 Like

It Works like a charm.
But i’m having one issue, when i hit backspace te cursor is aways going to the end of the input.
i can’t make it work the backspace as it should be.
can you help ?

When i hit backspace te cursor is aways going to the end of the input. Someone resolved?

I´ve added this into backspace event to avoid the strange behavior

onInputChange(event) {
  if(event.key != "Backspace" || event.keyCode != 8 ){
    this.modelValue = this.getModelValue(event);
    let stringToFormat = this.modelValue;
    if (stringToFormat.length < 10) {
        stringToFormat = this.padString(stringToFormat);
    }

    this.viewValue = this.format(stringToFormat);
    this.writeValue(event.target, this.viewValue);
  }
}

Quando apago uma letra o cursor tem um comportamento estranho. Alguém resolveu?

https://github.com/jalescardoso/ionic-mask/blob/master/README.md

How can I do this now on ionic 2? on @component is not working

Just need to add on @NgModules → declarations on app.module.ts.

Sorry guys, I just google it

Inspired by examples provided by @mhartington and @ederibeiro above, I created an input mask directive that applies and removes leading and trailing formatting to the ordinal position of the input field caret as you type or backspace instead of applying padded formatting (which makes the cursor display at the end of the padded input value and is a sub-optimal user experience especially for progressive web apps).

Here’s the Ionic 2 & 3 Input Mask Directive Gist:
https://gist.github.com/JoeMeeks/e7932fa291ba1c7e1e66597e5b52c633

URL is not working now?

I solved using some of your code:

if(event.key != “Backspace” || event.keyCode != 8 )
{
this.modelValue = this.getModelValue(event);
var stringToFormat = this.modelValue;

  /*if (stringToFormat.length < 12) 
  {
      stringToFormat = this.padString(stringToFormat);
  }*/

  this.viewValue = this.format(stringToFormat);
  this.writeValue(event.target, this.viewValue);
}

Its work nice for me, tks a lot for all the contribution for this.

I’ve created a generic directive to allow dynamic masks (because sometimes the mask could change, according to value, like credit cards and phone numbers in some countries):

import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core';
import { NgControl } from '@angular/forms';

import { MaskGenerator } from '../interfaces/mask-generator.interface';

@Directive({
    selector: '[spMask]' 
})
export class MaskDirective {

    private static readonly ALPHA = 'A';
    private static readonly NUMERIC = '9';
    private static readonly ALPHANUMERIC = '?';
    private static readonly REGEX_MAP = new Map([
        [MaskDirective.ALPHA, /\w/],
        [MaskDirective.NUMERIC, /\d/],
        [MaskDirective.ALPHANUMERIC, /\w|\d/],
    ]);

    private value: string = null;
    private displayValue: string = null;

    @Input('spMask') 
    public maskGenerator: MaskGenerator;

    @Input('spKeepMask') 
    public keepMask: boolean;

    @Input('spMaskValue') 
    public set maskValue(value: string) {
        if (value !== this.value) {
            this.value = value;
            this.defineValue();
        }
    };

    @Output('spMaskValueChange') 
    public changeEmitter = new EventEmitter<string>();

    @HostListener('input', ['$event'])
    public onInput(event: { target: { value?: string }}): void {
        let target = event.target;
        let value = target.value;
        this.onValueChange(value);
    }

    constructor(private ngControl: NgControl) { }

    private updateValue(value: string) {
        this.value = value;
        this.changeEmitter.emit(value);
        MaskDirective.delay().then(
            () => this.ngControl.control.updateValueAndValidity()
        );
    }

    private defineValue() {
        let value: string = this.value;
        let displayValue: string = null;

        if (this.maskGenerator) {
            let mask = this.maskGenerator.generateMask(value);

            if (value != null) {
                displayValue = MaskDirective.mask(value, mask);
                value = MaskDirective.processValue(displayValue, mask, this.keepMask);
            }   
        } else {
            displayValue = this.value;
        }

        MaskDirective.delay().then(() => {
            if (this.displayValue !== displayValue) {
                this.displayValue = displayValue;
                this.ngControl.control.setValue(displayValue);
                return MaskDirective.delay();
            }
        }).then(() => {
            if (value != this.value) {
                return this.updateValue(value);
            }
        });
    }

    private onValueChange(newValue: string) {
        if (newValue !== this.displayValue) {
            let displayValue = newValue;
            let value = newValue;

            if ((newValue == null) || (newValue.trim() === '')) {
                value = null;
            } else if (this.maskGenerator) {
                let mask = this.maskGenerator.generateMask(newValue);
                displayValue = MaskDirective.mask(newValue, mask);
                value = MaskDirective.processValue(displayValue, mask, this.keepMask);
            }

            this.displayValue = displayValue;

            if (newValue !== displayValue) {
                this.ngControl.control.setValue(displayValue);
            }

            if (value !== this.value) {
                this.updateValue(value);
            }
        }
    }

    private static processValue(displayValue: string, mask: string, keepMask: boolean) {
        let value = keepMask ? displayValue : MaskDirective.unmask(displayValue, mask);
        return value
    }

    private static mask(value: string, mask: string): string {
        value = value.toString();

        let len = value.length;
        let maskLen = mask.length;
        let pos = 0;
        let newValue = '';

        for (let i = 0; i < Math.min(len, maskLen); i++) {
            let maskChar = mask.charAt(i);
            let newChar = value.charAt(pos);
            let regex: RegExp = MaskDirective.REGEX_MAP.get(maskChar);

            if (regex) {
                pos++;

                if (regex.test(newChar)) {
                    newValue += newChar;
                } else {
                    i--;
                    len--;
                }
            } else {
                if (maskChar === newChar) {
                    pos++;
                } else {
                    len++;
                }

                newValue += maskChar;
            }
        }       

        return newValue;
    }

    private static unmask(maskedValue: string, mask: string): string {
        let maskLen = (mask && mask.length) || 0;
        return maskedValue.split('').filter(
            (currChar, idx) => (idx < maskLen) && MaskDirective.REGEX_MAP.has(mask[idx])
        ).join('');
    }

    private static delay(ms: number = 0): Promise<void> {
        return new Promise(resolve => setTimeout(() => resolve(), ms)).then(() => null);
    }
}

The interface is:

export interface MaskGenerator {
    generateMask: (value: string) => string;
}

This way the mask can change when the value change (like (999) 999-9999 for 10 or less digits and (999) 9999-9999 for 11 digits, and blocking the user to write more digits).

Here is how you can use it: