Angular 2, трудности с проверкой данных и маской ввода
Я выполнил проверку формы в соответствии с 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;
}
плюс для этого элемента я понял каталог ввода маски: http://pastebin.com/wRzHSsVy
Возникает следующая проблема: при вводе телефонного номера сначала выполняется проверка, а затем - каталог маски ввода. Таким образом, данные, проверяемые валидатором, и данные, формируемые каталогом маски ввода, различаются. Например, номер телефона на валидаторе - (888) -888-88882, и маска преобразует номер в следующий формат (888) -888-8888, но валидатор уже сработал и указал ошибку до активации маски.
2 ответа
После небольшого исследования я нашел обходной путь. Конечно, он немного грязный.
Мой класс маски прикреплялся к событиям (input) и (keyup.backspace):
...
host: {
'(input)': 'onInputChange($event.target.value)',
'(keyup.backspace)': 'onInputChange($event.target.value, true)'
}
...
Вместо этого я привязался к (размытие) и (фокус) событиям.
...
host: {
'(blur)': 'onInputChange($event.target.value)',
'(focus)': 'removeMask($event.target.value)'
}
...
На фокусе я удаляю маску, затем на размытии добавляю ее обратно. Это гарантирует, что валидатор будет получать правильное значение всякий раз, когда он изменяется, без вмешательства маскировки. Затем я изменил FormControl, чтобы использовать числовой валидатор, а не валидатор телефона, так как проверяемое значение не будет применять маску.
маска телефона:
@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;
}
}
числовой валидатор:
export function validateNumeric(control: FormControl) {
let regex = /[0-9]+/;
return !control.value || regex.test(control.value) ? null : { numeric: { valid: false } };
}
У меня очень похожая проблема, также с маской / валидатором телефона. Первоначально я думал о том, чтобы как-нибудь повторно вызвать проверку после вызова "this.control.valueAccessor.writeValue(...)" в моей маске.
Моя попытка была добавить:
this.control.control.updateValueAndValidity(
{
onlySelf: true,
emitEvent: false
});
Похоже, что это снова запускает проверку формы, но значение, переданное в валидатор, по-прежнему является неправильным (предварительно маскированным) значением.
Тем не менее, я не использую [(ngModel)] в своих входных данных, так что вы можете быть кандидатом, чтобы использовать что-то вроде этого поста предлагает