-
-
Save JoeMeeks/e7932fa291ba1c7e1e66597e5b52c633 to your computer and use it in GitHub Desktop.
<ion-input type="tel" pattern="\d*" placeholder="(xxx) xxx-xxxx" mask="(***) ***-****" [(ngModel)]="phone" name="phone"></ion-input> | |
<ion-input type="tel" pattern="\d*" placeholder="xxx-xx-xxxx" mask="***-**-****" [(ngModel)]="ssn" name="ssn"></ion-input> |
import { Directive, Attribute } from '@angular/core'; | |
@Directive({ | |
selector: '[mask]', | |
host: { | |
'(keyup)': 'onInputChange($event)' | |
} | |
}) | |
export class InputMask { | |
pattern: string; | |
constructor( | |
@Attribute('mask') pattern: string | |
) { | |
this.pattern = pattern; | |
} | |
onInputChange(e) { | |
try { | |
let value = e.target.value, | |
caret = e.target.selectionStart, | |
pattern = this.pattern, | |
reserve = pattern.replace(/\*/, 'g'), | |
applied = '', | |
ordinal = 0; | |
if (e.keyCode === 8 || e.key === 'Backspace' || e.keyCode === 46 || e.key === 'Delete') { | |
if (value.length) { | |
//remove all trailing formatting | |
while (value.length && pattern[value.length] && pattern[value.length] !== '*') { | |
value = value.substring(0, value.length - 1); | |
} | |
//remove all leading formatting to restore placeholder | |
if (pattern.substring(0, value.length).indexOf('*') < 0) { | |
value = value.substring(0, value.length - 1); | |
} | |
} | |
} | |
//apply mask characters | |
for (var i = 0; i < value.length; i++) { | |
//enforce pattern limit | |
if (i < pattern.length) { | |
//match mask | |
if (value[i] === pattern[ordinal]) { | |
applied += value[i]; | |
ordinal++; | |
} else if (reserve.indexOf(value[i]) > -1) { | |
//skip other reserved characters | |
} else { | |
//apply leading formatting | |
while (ordinal < pattern.length && pattern[ordinal] !== '*') { | |
applied += pattern[ordinal]; | |
ordinal++; | |
} | |
applied += value[i]; | |
ordinal++; | |
//apply trailing formatting | |
while (ordinal < pattern.length && pattern[ordinal] !== '*') { | |
applied += pattern[ordinal]; | |
ordinal++; | |
} | |
} | |
} | |
} | |
e.target.value = applied; | |
if (caret < value.length) { | |
e.target.setSelectionRange(caret, caret); | |
} | |
} catch (ex) { | |
console.error(ex.message); | |
} | |
} | |
} |
OK, removing type="number"
solves the warning.. now directive seems to work, but id does not follow the pattern correctly. It apllies only one dash -
in pattern and on incorrect position :/ Example 18616811151-51351135135151
Even when I try without formBuilder it is buggy, sometimes it mask the value and sometimes it does not.. :/
ionic info:
cli packages: (/Users/lucky/Documents/projects/tatramat/client/node_modules)
@ionic/cli-plugin-cordova : 1.6.2
@ionic/cli-plugin-ionic-angular : 1.4.1
@ionic/cli-utils : 1.7.0
ionic (Ionic CLI) : 3.7.0
global packages:
Cordova CLI : 7.0.1
local packages:
@ionic/app-scripts : 1.2.5
Cordova Platforms : android 6.2.3 browser 4.1.0 ios 4.4.0
Ionic Framework : ionic-angular 2.3.0
System:
Node : v6.9.5
OS : macOS Sierra
Xcode : Xcode 8.3.3 Build version 8E3004b
ios-deploy : 1.9.1
ios-sim : 5.0.13
npm : 5.3.0
Great job it's working for me
thanks
and yes @coicoronado thanks to you also
@coicoronado, @luckylooke, @niravjadatiya This has been updated to fix a critical Delete key input bug. Also the code is now far more efficient, performant, and has the added behavior to retain caret position.
@JoeMeeks this directive works great, thanks for the code!
It doesn't work with input type="number".
It doesn't work with input type='number'
Thank you a lot for this!
Quick question to @JoeMeeks : I have a field which can hold 2 types of values, depending on a radio button clicked by the user. How can I change the mask based on the type chosen by the user, realtime?
@JoeMeeks this is really cool! Since you can safely assume this directive is only tied to an input component, you can do something like this to ensure that the mask gets applied on first render, as well:
https://gist.github.com/codinronan/d6ddfc4ab8dba2277386dbed160b050e
@BlacksmithVRS my GitHub notification settings were not letting me know about mentions so I apologize for the late reply. Have you tried:
<ion-input type="tel" pattern="\d*" placeholder="(xxx) xxx-xxxx" [mask]="publicMaskVar" [(ngModel)]="phone" name="phone"></ion-input>
with publicMaskVar being assigned with the (ionChange) handler of your radio input?
@codinconan nice ngAfterViewInit implementation!
thanks man! you saved my day!
@JoeMeeks nice work, how to use this directive for thousand separator?
DOES NOT WORK FOR ME :/
Using:
tried also with
Typing 7th number clears the input.
Warning occures in console:
The specified value "135135-" is not a valid number. The value must match to the following regular expression: -?(\d+|\d+\.\d+|\.\d+)([eE][-+]?\d+)?
Tested also with @coicoronado update, because I am using form builder.