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)] в своих входных данных, так что вы можете быть кандидатом, чтобы использовать что-то вроде этого поста предлагает

Другие вопросы по тегам