提问人:FaBEEola 提问时间:10/17/2023 最后编辑:FaBEEola 更新时间:10/18/2023 访问量:94
根据 <input type=“number” 的 NaN 值进行验证>
Validate against NaN values for <input type="number">
问:
我正在使用 Angular Reactive 表单创建一个表单,出于 UX 原因,当在字段中插入某些无效值(例如负数或非整数)时,我尝试禁用表单的提交。<input type="number">
问题是,当我插入一个值时,即使允许,通常也会计算为 ,例如,单独的字母、后面没有数字的减号或加号,甚至是一个太大而无法用 TypeScript 表示的数字,而是在通过 或 访问值时计算为 。<input type="number">
NaN
e
number
null
control.value
control.getRawValue()
编辑:当输入字段为空时,表单也需要可提交。可悲的是,这是一个不可协商的要求,我也不能像字段那样使用默认值。0
这是我尝试过的最小可重现示例(它只尝试阻止 NaN 值)。
app.component.ts
import { Component } from '@angular/core';
import { AbstractControl, FormBuilder, ValidatorFn } from '@angular/forms';
@Component({
selector: 'app-root',
template: `
<form [formGroup]="formGroup" (ngSubmit)="print()">
<input type="number" name="control" id="control" formControlName="control" >
<button type="submit" [disabled] ="formGroup.invalid">print</button>
</form>
`
})
export class AppComponent {
title = 'ReactiveFormNumberControl';
formGroup
constructor(private _fb: FormBuilder) {
this.formGroup = this._fb.group({
control: this._fb.control<number | null>(null, {
validators: [noNaNValidator]
})
})
}
print = () => {
console.log(this.formGroup.value)
}
}
const noNaNValidator: ValidatorFn = (
control: AbstractControl<number | null>,
) => {
const value = control.value
if (Number.isNaN(value)) {
// Value is null and not NaN, so this is never reached because Number.isNaN(null) is false,
// the control (and group) is marked valid and the submit button is not disabled
return {
invalidValue: {
value: value
},
}
}
return null
}
答:
NumberValueAccessor 负责将每个无效值转换为 .null
这是预期行为。
评论
NumberValueAccessor
在我不确定这是否适用于让 2 个指令匹配相同的输入!FormsModule
要检查一个值是否为 ,如果可能的话,您应该首先将该值转换为数字,然后使用 方法 ,在您的示例中,您可以尝试:NaN
Number.isNaN()
const value: any = control.value;
const parsedValue = parseFloat(value);
if (Number.isNaN(parsedValue)) {
// Value is null and not NaN, so this is never reached because Number.isNaN(null) is false,
// the control (and group) is marked valid and the submit button is not disabled
return {
invalidValue: {
value: value
}
}
}
评论
Number.isNaN(parsedValue)
parsedValue && Number.isNaN(parsedValue)
e
-
在 GitHub 上查看与此相关的 Angular 问题时,更准确地说是问题 #2962,我发现了一种解决方法,利用某些类型的元素中存在的 HTML5 属性。badInput
<input>
number
我编写了一个自定义验证器指令,类似于 Angular Issue #2962 评论中显示的指令,但与该指令不同的是,我编写的指令必须显式应用,并且现在只能应用于字段(但如果需要,通过更改指令的 )。<input type="number">
selector
bad-input-validator.directive.ts
import { Directive, ElementRef } from '@angular/core';
import { AbstractControl, NG_VALIDATORS, ValidationErrors, Validator } from '@angular/forms';
@Directive({
selector: 'input[type=number][appBadInputValidator]',
standalone: true,
providers: [{
provide: NG_VALIDATORS,
useExisting: BadInputValidatorDirective,
multi: true,
}]
})
export class BadInputValidatorDirective implements Validator {
private onChangeCallback?: () => void;
constructor(private _element: ElementRef) { }
validate(_: AbstractControl): ValidationErrors | null {
const inputElement = this._element.nativeElement
return inputElement.validity.badInput ? { 'badInput': true } : null
}
registerOnValidatorChange?(fn: () => void): void {
this.onChangeCallback = fn
}
}
这可能可以以某种方式改进,但现在它做了我需要做的事情。当我将 应用于一个元素,并输入一个值,该值将解析为 ,并被标记为无效,并且提交按钮被正确禁用。appBadInputValidator
<input type="number">
NaN
FormControl
FormGroup
该指令的工作方式类似于 Angular.JS 的表单验证,它跟踪 ,但此行为目前在 Angular 中不存在,至少从 16.2.6 版本开始。badInput
非常感谢 GitHub 上的 amc1804 发布解决方案。
评论