Angular 2, difficulties with data validation and input mask

I implemented form validation in accordance with https://auth0.com/blog/angular-2-series-part-5-forms-and-custom-validation/

<input class="form-control" type="text" name="phone" autocomplete="off" placeholder="(XXX)-XXX-XXXX" mask="" [disabled]="disabled" [(ngModel)]="candidate.phone" ngControl="phone"/> 

...

...

 static phone(control: Control): ValidationResult { let URL_REGEXP = /^\(\d{3}\)-\d{3}-\d{4}$/i; if (control.value && (control.value.length <= 5 || !URL_REGEXP.test(control.value))) { return {"phone": true}; } return null; } 

plus for this element I understood the input mask directory: http://pastebin.com/wRzHSsVy

The following problem occurs: when entering a phone number, a check is performed first, and then a catalog of input masks. Thus, the data verified by the validator and the data generated by the input mask directory are different. For example, the phone number on the validator is (888) -888-88882, and the mask turns the number into the following format (888) -888-8888, but the validator already worked and indicated an error before activating the mask.

+5
source share
2 answers

I have a very similar problem, also using a mask / validator. My initial thought was to somehow re-invoke the validation after calling "this.control.valueAccessor.writeValue (...)" in my mask.

My attempt was to add:

 this.control.control.updateValueAndValidity( { onlySelf: true, emitEvent: false }); 

This is like re-validating the form, but the value passed to the validator is still the wrong (pre-masked) value.

However, I do not use [(ngModel)] in my input, so you can be a candidate for using something like this post .

0
source

After a little research, I found a workaround. Of course, he feels a little dirty.

My mask class was attached to events (input) and (keyup.backspace):

 ... host: { '(input)': 'onInputChange($event.target.value)', '(keyup.backspace)': 'onInputChange($event.target.value, true)' } ... 

Instead, I became attached to (blur) and (focus) events.

 ... host: { '(blur)': 'onInputChange($event.target.value)', '(focus)': 'removeMask($event.target.value)' } ... 

In focus, I remove the mask, and then blur it, add it back. This ensures that the validator gets the correct value whenever it changes, without masking intervention. Then I changed FormControl to use a numerical validator, not a phone validator, since the value being checked will not be applied to the mask.

phone mask:

 @Directive({ selector: '[phoneMask]', host: { '(blur)': 'onInputChange($event.target.value)', '(focus)': 'removeMask($event.target.value)' } }) export class PhoneMask { constructor(public control: NgControl) { } onInputChange(value) { // remove all mask characters (keep only numeric) var newVal = value.replace(/\D/g, ''); // non-digits // set the new value this.control.valueAccessor.writeValue(PhoneMask.applyMask(newVal)); } removeMask(value) { this.control.valueAccessor.writeValue(value.replace(/\D/g, '')); } static applyMask(value: string): string { if (value.length == 0) { value = ''; } else if (value.length <= 3) { value = value.replace(/^(\d{0,3})/, '($1)'); } else if (value.length <= 6) { value = value.replace(/^(\d{0,3})(\d{0,3})/, '($1) $2'); } else { value = value.replace(/^(\d{0,3})(\d{0,3})(.*)/, '($1) $2-$3'); } return value; } } 

numeric validator:

 export function validateNumeric(control: FormControl) { let regex = /[0-9]+/; return !control.value || regex.test(control.value) ? null : { numeric: { valid: false } }; } 
0
source

All Articles