I want to mask my input
value, basically I have an input field for credit card expiry date and want to mask it in format mm/yy
, this is what I had tried :
input-mask.directive.ts
import { Directive, HostListener } from '@angular/core';
import { NgControl } from '@angular/forms';
@Directive({
selector: '[formControlName][appInputMask]',
})
export class InputMaskDirective {
@HostListener('input', ['$event'])
onKeyDown(event: KeyboardEvent) {
const input = event.target as HTMLInputElement;
const trimmed = input.value.replace(/\s+/g, '').slice(0, 4);
if (trimmed.length > 3) {
return (input.value = `${trimmed.slice(0, 2)}/${trimmed.slice(2)}`);
}
}
}
I got my expected output, but the problem is when using backspace on input field, it messed up, here is my demo on stackblitz, how to solve this? or is there any better approach on input mask?
HTMLInput element's maxlength should be 5 otherwise it won't allow a user to add 4 digits once you programmatically add a slash in it.
The same issue exist in const trimmed = input.value.replace(/\s+/g, '').slice(0,4);
If it contains a slash, the slice should be end at 5 instead of 4.
In return
statement
return (input.value = `${trimmed.slice(0, 2)}/${trimmed.slice(2)}`);
If the slash is added once, the ${trimmed.slice(2)
will return /\d{1,2}
. So you need to avoid the slash and start from 3.
change max length to 5 from 4
<input ... maxlength="5">
Now, input-mask.directive.ts need some changes
Change
const trimmed = input.value.replace(/\s+/g, '').slice(0,4);
to
const trimmed = input.value.replace(/\s+/g, '').slice(0, input.value.indexOf('/')==-1?4:5);
Because when you add /
, the length will become 5.
Don't use
.slice(0)
because it allows a user to paste 5 digits and when you add a slash, it'll become 6. So the date will look like11/111
instead of11/11
Change
return (input.value = `${trimmed.slice(0, 2)}/${trimmed.slice(2)}`);
to
return (input.value = `${trimmed.slice(0, 2)}/${trimmed.slice(trimmed.indexOf('/')==-1?2:3)}`);
This is where your code getting messed up. If it contains a slash, then you should slice it from 3. Else slice it from 2.
final code of HostListener in input-mask directive
@HostListener('input', ['$event'])
onKeyDown(event: KeyboardEvent) {
const input = event.target as HTMLInputElement;
const trimmed = input.value.replace(/\s+/g, '').slice(0, input.value.indexOf('/')==-1?4:5);
if (trimmed.length > 3) {
return (input.value = `${trimmed.slice(0, 2)}/${trimmed.slice(trimmed.indexOf('/')==-1?2:3)}`);
}
}
Working example : stackblitz