Is it possible to have model-driven form in Angular 2 and implement a directive that would allow to mask an input
field like a phone number entry (123) 123-4567
?
相关问题
- Angular RxJS mergeMap types
- Laravel Option Select - Default Issue
- npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fs
- HTML form is not sending $_POST values
- How to use Control.FromHandle?
相关文章
- angular脚手架在ie9+下兼容问题
- angular 前端项目 build 报错 "Cannot find module 'le
- 放在input的text下文本一直出现一个/(即使还没输入任何值)是什么情况
- Angular Material Stepper causes mat-formfield to v
- After upgrade to Angular 9 cannot find variable in
- is there any difference between import { Observabl
- Suppress “Circular dependency detected” suppress w
- How can you get current positional information abo
Combining Günter Zöchbauer's answer with good-old vanilla-JS, here is a directive with two lines of logic that supports (123) 456-7890 format.
Reactive Forms: Plunk
Template-driven Forms: Plunk
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
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:
Plunker >= RC.5
original
One way you could do it is using a directive that injects
NgControl
and manipulates the value(for details see inline comments)
Plunker example <= RC.5
Angular 4+
I've created a generic directive, able to receive any mask and also able to define the mask dynamically based on the value:
mask.directive.ts:
(Remember to declare it in your NgModule)
The numeric character in the mask is
9
so your mask would be(999) 999-9999
. You can change theNUMERIC
static field if you want (if you change it to0
, your mask should be(000) 000-0000
, for example).The value is displayed with mask but stored in the component field without mask (this is the desirable behaviour in my case). You can make it be stored with mask using
[spKeepMask]="true"
.The directive receives an object that implements the
MaskGenerator
interface.mask-generator.interface.ts:
This way it's possible to define the mask dynamically based on the value (like credit cards).
I've created an utilitarian class to store the masks, but you can specify it directly in your component too.
my-mask.util.ts:
Then you can use it in your component (use
spMaskValue
instead ofngModel
, but if is not a reactive form, usengModel
with nothing, like in the example below, just so that you won't receive an error of no provider because of the injectedNgControl
in the directive; in reactive forms you don't need to includengModel
):my.component.ts:
my.component.html:
(Take a look at
phone02
and see that when you type 1 more digit, the mask changes; also, look that the value stored ofphone01
is without mask)I've tested it with normal inputs as well as with
ionic
inputs (ion-input
), with both reactive (withformControlName
, not withformControl
) and non-reactive forms.Reactive Form
See at Stackblitz
Addition to the @Günter Zöchbauer's answer above, I tried as follows and it seems to be working but I'm not sure whether it is a efficient way.
I use
valueChanges
observable to listen for change events in the reactive form by subscribing to it. For special handling of backspace, I get thedata
from subscribe and check it withuserForm.value.phone(from [formGroup]="userForm")
. Because, at that moment, the data changes to the new value but the latter refers to the previous value because of not setting yet. If the data is less than previous value then the user should remove character from input. In this case, change pattern as follows:from :
newVal = newVal.replace(/^(\d{0,3})/, '($1)');
to :
newVal = newVal.replace(/^(\d{0,3})/, '($1');
Otherwise, as Günter Zöchbauer mentioned above, deleting of non-numeric characters is not recognized because when we remove parentheses from input, digits still remain the same and added again parentheses from pattern match.
Controller:
Template:
UPDATE
Define an id
<input id="tel" formControlName="phone" #phoneRef>
and renderer2#selectRootElement to get the native element in the component.So we can get the cursor position using:
and then we can apply it after the input is updated to new value:
UPDATE 2
I also put the logic into a directive. This makes it easier to apply it to other elements.
See at Stackblitz
Note: It is specific to
(123) 123-4567
pattern.It can be done using a directive. Below is the plunker of the input mask I built.
https://plnkr.co/edit/hRsmd0EKci6rjGmnYFRr?p=preview
Code:
}
Note: there are still a few bugs.
you can use cleave.js
demo: https://jsfiddle.net/emirM/a8fogse1/