Angular5 and 6:
angular 5 and 6 recommended way is to use @HostBindings and @HostListeners instead of the host property
remove host and add @HostListener
@HostListener('ngModelChange', ['$event']) onModelChange(event) { this.onInputChange(event, false); } @HostListener('keydown.backspace', ['$event']) keydownBackspace(event) { this.onInputChange(event.target.value, true); }
Working Online stackblitz Link: https://angular6-phone-mask.stackblitz.io
Stackblitz Code example: https://stackblitz.com/edit/angular6-phone-mask
Official documentation link https://angular.io/guide/attribute-directives#respond-to-user-initiated-events
Angular2 and 4:
original
One way you could do it is using a directive that injects NgControl
and manipulates the value
(for details see inline comments)
@Directive({ selector: '[ngModel][phone]', host: { '(ngModelChange)': 'onInputChange($event)', '(keydown.backspace)': 'onInputChange($event.target.value, true)' } }) export class PhoneMask { constructor(public model: NgControl) {} onInputChange(event, backspace) { // remove all mask characters (keep only numeric) var newVal = event.replace(/\D/g, ''); // special handling of backspace necessary otherwise // deleting of non-numeric characters is not recognized // this laves room for improvement for example if you delete in the // middle of the string if (backspace) { newVal = newVal.substring(0, newVal.length - 1); } // don't show braces for empty value if (newVal.length == 0) { newVal = ''; } // don't show braces for empty groups at the end else if (newVal.length <= 3) { newVal = newVal.replace(/^(\d{0,3})/, '($1)'); } else if (newVal.length <= 6) { newVal = newVal.replace(/^(\d{0,3})(\d{0,3})/, '($1) ($2)'); } else { newVal = newVal.replace(/^(\d{0,3})(\d{0,3})(.*)/, '($1) ($2)-$3'); } // set the new value this.model.valueAccessor.writeValue(newVal); } }
@Component({ selector: 'my-app', providers: [], template: ` <form [ngFormModel]="form"> <input type="text" phone [(ngModel)]="data" ngControl="phone"> </form> `, directives: [PhoneMask] }) export class App { constructor(fb: FormBuilder) { this.form = fb.group({ phone: [''] }) } }