Тип входного номера "только числовое значение"
Как я могу проверить правильность ввода type="number"
только если значение является числовым или нулевым, используя только Reactive Forms (без директив)?
Только цифры [0-9]
и. не допускаются, "е" или любые другие символы.
Что я пробовал до сих пор:
Шаблон:
<form [formGroup]="form" novalidate>
<input type="number" formControlName="number" id="number">
</form>
Составная часть:
export class App {
form: FormGroup = new FormGroup({});
constructor(
private fb: FormBuilder,
) {
this.form = fb.group({
number: ['', [CustomValidator.numeric]]
})
}
}
CustomValidator:
export class CustomValidator{
// Number only validation
static numeric(control: AbstractControl) {
let val = control.value;
if (val === null || val === '') return null;
if (!val.toString().match(/^[0-9]+(\.?[0-9]+)?$/)) return { 'invalidNumber': true };
return null;
}
}
Проблема в том, что когда пользователь вводит что-то, что не является числом ("123e" или "abc"), значение FormControl становится null
, имейте в виду, я не хочу, чтобы поле было обязательным, поэтому, если поле действительно является пустым null
значением должно быть в силе.
Кросс-браузерная поддержка также важна (поля ввода чисел Chrome не позволяют пользователю вводить буквы - кроме "e", но FireFox и Safari делают).
Ответы
Ответ 1
В HTML файл вы можете добавить шаблон ngIf для вас, как это
<div class="form-control-feedback" *ngIf="Mobile.errors && (Mobile.dirty || Mobile.touched)">
<p *ngIf="Mobile.errors.pattern" class="text-danger">Number Only</p>
</div>
В файл .ts вы можете добавить шаблон Validators - "^ [0-9] * $"
this.Mobile = new FormControl('', [
Validators.required,
Validators.pattern("^[0-9]*$"),
Validators.minLength(8),
]);
Ответ 2
Самый простой способ - использовать библиотеку, подобную этой one и, в частности, вы хотите, чтобы noStrings
был истинным
export class CustomValidator{ // Number only validation
static numeric(control: AbstractControl) {
let val = control.value;
const hasError = validate({val: val}, {val: {numericality: {noStrings: true}}});
if (hasError) return null;
return val;
}
}
Ответ 3
Вам нужно использовать регулярные выражения в своем настраиваемом валидаторе. Например, здесь код, который позволяет вводить только 9 цифр в поля ввода:
function ssnValidator(control: FormControl): {[key: string]: any} {
const value: string = control.value || '';
const valid = value.match(/^\d{9}$/);
return valid ? null : {ssn: true};
}
Посмотрите пример приложения здесь:
https://github.com/Farata/angular2typescript/tree/master/Angular4/form-samples/src/app/reactive-validator
Ответ 4
Иногда проще просто попробовать что-то простое.
validateNumber(control: FormControl): { [s: string]: boolean } {
//revised to reflect null as an acceptable value
if (control.value === null) return null;
// check to see if the control value is no a number
if (isNaN(control.value)) {
return { 'NaN': true };
}
return null;
}
Надеюсь, что это поможет.
обновлено в соответствии с комментарием,
Вам нужно вызвать валидатор следующим образом
number: new FormControl('',[this.validateNumber.bind(this)])
Связывание (this) необходимо, если вы помещаете валидатор в компонент, который, как я это делаю.
Ответ 5
У меня тоже была похожая проблема: я хотел числа и ноль в поле ввода, которое не требуется. Проработал ряд различных вариаций. Я наконец остановился на этом, который, кажется, делает свое дело. Вы помещаете директиву ntvFormValidity
в любой элемент управления формы, который имеет собственную недействительность и не превращает это недопустимое состояние в ng-invalid.
Пример использования: <input type="number" formControlName="num" placeholder="0" ntvFormValidity>
Определение директивы:
import { Directive, Host, Self, ElementRef, AfterViewInit } from '@angular/core';
import { FormControlName, FormControl, Validators } from '@angular/forms';
@Directive({
selector: '[ntvFormValidity]'
})
export class NtvFormControlValidityDirective implements AfterViewInit {
constructor(@Host() private cn: FormControlName, @Host() private el: ElementRef) { }
/*
- Angular doesn't fire "change" events for invalid <input type="number">
- We have to check the DOM object for browser native invalid state
- Add custom validator that checks native invalidity
*/
ngAfterViewInit() {
var control: FormControl = this.cn.control;
// Bridge native invalid to ng-invalid via Validators
const ntvValidator = () => !this.el.nativeElement.validity.valid ? { error: "invalid" } : null;
const v_fn = control.validator;
control.setValidators(v_fn ? Validators.compose([v_fn, ntvValidator]) : ntvValidator);
setTimeout(()=>control.updateValueAndValidity(), 0);
}
}
Задача состояла в том, чтобы получить ElementRef из FormControl, чтобы я мог его изучить. Я знаю там @ViewChild, но я не хотел аннотировать каждое числовое поле ввода идентификатором и передавать его чему-то другому. Итак, я построил директиву, которая может запросить ElementRef.
В Safari для приведенного выше примера HTML Angular помечает элемент управления формы как недопустимый для таких вводов, как "abc".
Я думаю, что если бы я сделал это снова, я бы, вероятно, создал свой собственный CVA для числовых полей ввода, поскольку это обеспечило бы еще больший контроль и сделал бы простой HTML.
Что-то вроде этого:
<my-input-number formControlName="num" placeholder="0">
PS: Если есть лучший способ получить FormControl для директивы, я полагаю, с помощью Dependency Injection и providers
в декларации, пожалуйста, дайте мне знать, чтобы я мог обновить свою директиву (и этот ответ).