输入类型号“仅数值”验证
Posted
技术标签:
【中文标题】输入类型号“仅数值”验证【英文标题】:Input type number "only numeric value" validation 【发布时间】:2017-12-16 21:28:54 【问题描述】:我如何验证 type="number"
的输入仅在值是数字或 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;
Plunker
问题是当用户输入不是数字的内容时(“123e”或“abc”) FormControl 的值变为null
,请记住我不想要该字段是必需的,因此如果该字段确实为空,null
值应该是有效的。
跨浏览器支持也很重要(Chrome 的数字输入字段不允许用户输入字母 - “e”除外,但 FireFox 和 Safari 可以)。
【问题讨论】:
你有没有找到一个可以接受的答案?当我决定从type="text"
切换到type="number"
时,我遇到了同样的问题。我不明白为什么 Angular 会更改控件的值,但对有效性没有做任何事情。对我来说似乎是一个错误。
对于所描述的确切情况,没有。不幸的是……
所以我还没有实现这个,但我计划实现一个自定义ControlValueAccessor
来克服这种行为。我已经有一个自定义日期控件,它执行类似于将符合 ISO 标准的日期字符串存储在表单值中的操作,而不是输入中显示的“10/16/2018”字符串。一旦我希望在本月的某个时候遇到关于 type="number"
的错误,我将在这里添加我的解决方案。
我也有这个问题。 AngularJS 有一个内置的数字验证器,可以使用 ng-messages="number" 访问,它没有这个问题。有些东西正在拦截非数字输入并将其清除。
github.com/angular/angular/issues/11644 描述了该问题。此处引用:github.com/angular/angular/issues/2962
【参考方案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
文件中,您可以添加验证器模式 -"^[0-9]*$"
this.Mobile = new FormControl('', [
Validators.required,
Validators.pattern("^[0-9]*$"),
Validators.minLength(8),
]);
【讨论】:
要求该字段可以为空,数字类型,不使用指令,如果它真的不为空,则只允许数字 0-9。请提供您的解决方案的工作预览,这个答案真的不是。仅限数字
@mihailo 你在 *ngif 中添加了 mobile.errors.required 所以,它不允许空值。 对为什么有这么多赞成票感到困惑。它没有完全回答这个问题。原始海报使用 【参考方案2】:使用指令变得简单,可以在整个应用程序中使用
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();
【讨论】:
【参考方案3】:最简单的方法是使用像 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;
【讨论】:
一旦输入包含字母,FormControls 值为 null,我该如何实现? 我编辑了答案,让您了解如何做到这一点 是的,谢谢,但这并不能解决问题的核心。如果输入包含字母let val = control.value = null
。这是一个问题,当它是数字类型时,角度如何解析输入值。如果输入是 text 类型,我的验证将完美运行。【参考方案4】:
我也遇到了类似的问题:我想要一个不需要的输入字段上的数字和 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 到 9 的数字。这在 Angular Cli 中对我有用
<input type="number" oninput="this.value=this.value.replace(/[^\d]/,'')" min=0>
【讨论】:
【参考方案6】:进行数字验证的最简单和最有效的方法是(它也会限制空格和特殊字符)
如果你不想限制长度,你可以删除 maxlength 属性
HTML
<input type="text" maxlength="3" (keypress)="validateNo($event)"/>
TS
validateNo(e): boolean
const charCode = e.which ? e.which : e.keyCode;
if (charCode > 31 && (charCode < 48 || charCode > 57))
return false
return true
【讨论】:
【参考方案7】:您需要在自定义验证器中使用正则表达式。例如,下面的代码只允许输入字段中包含 9 位数字:
function ssnValidator(control: FormControl): [key: string]: any
const value: string = control.value || '';
const valid = value.match(/^\d9$/);
return valid ? null : ssn: true;
在此处查看示例应用:
https://github.com/Farata/angular2typescript/tree/master/Angular4/form-samples/src/app/reactive-validator
【讨论】:
或者简单地用let regex = /\D+/; regex.exec("stringToT3est")
测试它。如果它不包含数字,它将返回 null。但这不适用于十进制符号。
我试过使用正则表达式,但这不是问题的核心。当输入是数字类型并且值不是数字(“123e”或“abc”)时,FormControl 的值变为null
...
好的,我现在明白你的问题了,这与 CustomValidator 内部的逻辑无关,而是如何首先获取输入而不是 null。是否可以将您的输入从类型编号更改为类型文本(或简单地将其删除并默认为文本)并以这种方式验证它?然后用户可以输入任何字符串,但验证器可以拒绝它
到目前为止我就是这样解决它的,但是当输入是 text 类型时,我失去了绑定到 number 类型输入的浏览器功能.主要是输入在移动设备上的作用方式。
恐怕对于这个用例,您必须将其保留为文本,如果您想要数字增量功能,构建自定义控件并不难。在 HTML 规范中,数字的输入文本将返回 null 值,例如“2e”,无法访问原始值:html.spec.whatwg.org/multipage/…【参考方案8】:
有时尝试这样简单的事情会更容易。
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)])
如果您将验证器放入组件中,则必须使用 bind(this),这就是我的做法。
【讨论】:
你测试了吗?当我在CustomValidator
(在我的 Plunker 中) 中使用 id 时,这不会验证
我让它在我的代码中运行,但没有放入 plunker,我会在几分钟后尝试设置示例,但我确实更新了答案以包含模板
请记住,问题的核心是 Firefox 和其他一些行为的方式。如果您输入了数字并且输入了"123e"
这不是数字并且输入的值是null
但我认为如果它的值是null
则输入有效。我发现唯一 100% 成功的方法是监听输入事件并检查键 + 复制/粘贴验证。
如果您希望 null 有效,那么只需检查 if (control.value === null) return null; 到允许 null 正常的代码。如果这是可以接受的,那么我将更改代码。
control.value === null
将在输入有123e
或为空时都为真。以上是关于输入类型号“仅数值”验证的主要内容,如果未能解决你的问题,请参考以下文章
Android中验证输入是否为汉字及手机号,邮箱验证,IP地址可用port号验证