如何仅使用Reactive Forms (无指令)来验证type="number"
的输入是否仅在数值为null时有效或为null?
只有数字[0-9]
和。是允许的,不是" e"或任何其他角色。
到目前为止我尝试过的事情:
<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]]
})
}
}
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;
}
}
问题是用户输入的内容不是数字(&#34; 123e&#34;或&#34; abc&#34;) FormControl的值变为null
,请注意我不希望该字段是必需的,因此如果该字段确实为空null
值应该有效。
跨浏览器支持也很重要(Chrome的数字输入字段不允许用户输入字母 - 除了&#34; e&#34;,但FireFox和Safari会这样做。)
答案 0 :(得分:18)
在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文件中,您可以添加验证器模式 - &#34; ^ [0-9] * $&#34;
this.Mobile = new FormControl('', [
Validators.required,
Validators.pattern("^[0-9]*$"),
Validators.minLength(8),
]);
答案 1 :(得分:1)
最简单的方法是使用像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;
}
}
答案 2 :(得分:0)
您需要在自定义验证程序中使用正则表达式。例如,这里的代码只允许输入字段中的9位数字:
function ssnValidator(control: FormControl): {[key: string]: any} {
const value: string = control.value || '';
const valid = value.match(/^\d{9}$/);
return valid ? null : {ssn: true};
}
在这里查看一个示例应用程序:
答案 3 :(得分:0)
有时候尝试像这样简单的事情会更容易。
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)是必要的。
答案 4 :(得分:0)
我也有类似的问题:我想要在不需要的输入字段上输入数字和null。经历了许多不同的变化。我终于选择了这个,似乎可以解决问题。您将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);
}
}
面临的挑战是从FormControl获取ElementRef,以便我可以对其进行检查。我知道有@ViewChild,但我不想用ID注释每个数字输入字段并将其传递给其他东西。因此,我建立了一个可以要求ElementRef的指令。
在Safari上,对于上面的HTML示例,Angular将表单控件标记为对诸如“ abc”之类的输入无效。
我认为,如果我要这样做,我可能会为数字输入字段构建自己的CVA,因为这将提供更多控制权并简化HTML。
类似这样的东西:
<my-input-number formControlName="num" placeholder="0">
PS:如果有更好的方法来获取该指令的FormControl,我猜想是依赖注入和声明中的providers
,请让我知道,以便我可以更新我的指令(以及此答案)
答案 5 :(得分:0)
使用指令变得容易并且可以在整个应用程序中使用
HTML
<input type="text" placeholder="Enter value" numbersOnly>
由于 .keyCode()
和 .which()
已弃用,因此使用 .key()
检查代码
转介from
指令:
@Directive({
selector: "[numbersOnly]"
})
export class NumbersOnlyDirective {
@Input() numbersOnly:boolean;
navigationKeys: Array<string> = ['Backspace']; //Add keys as per requirement
constructor(private _el: ElementRef) { }
@HostListener('keydown', ['$event']) onKeyDown(e: KeyboardEvent) {
if (
// Allow: Delete, Backspace, Tab, Escape, Enter, etc
this.navigationKeys.indexOf(e.key) > -1 ||
(e.key === 'a' && e.ctrlKey === true) || // Allow: Ctrl+A
(e.key === 'c' && e.ctrlKey === true) || // Allow: Ctrl+C
(e.key === 'v' && e.ctrlKey === true) || // Allow: Ctrl+V
(e.key === 'x' && e.ctrlKey === true) || // Allow: Ctrl+X
(e.key === 'a' && e.metaKey === true) || // Cmd+A (Mac)
(e.key === 'c' && e.metaKey === true) || // Cmd+C (Mac)
(e.key === 'v' && e.metaKey === true) || // Cmd+V (Mac)
(e.key === 'x' && e.metaKey === true) // Cmd+X (Mac)
) {
return; // let it happen, don't do anything
}
// Ensure that it is a number and stop the keypress
if (e.key === ' ' || isNaN(Number(e.key))) {
e.preventDefault();
}
}
}
答案 6 :(得分:0)
尽量减少输入,只允许输入 0 到 9 之间的数字。这在 Angular Cli 中对我有用
<input type="number" oninput="this.value=this.value.replace(/[^\d]/,'')" min=0>