我正在使用Angular Reactive表单创建一个表单,出于用户体验的原因,当在<input type="number">
字段中插入某些无效值时,我试图禁用表单的提交,例如负数或非整数。
问题是,当我插入一个值时,即使<input type="number">
允许,通常也会计算为NaN
,例如,单独的字母e
,后面没有数字的减号或加号,甚至是一个太大而无法用TypeScript number
表示的数字,而是在通过control.value
或control.getRawValue()
访问值时计算为null
。
编辑:当输入字段为空时,表单也需要可提交。遗憾的是,这是一个不可协商的要求,我也不能为该字段使用像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
}
3条答案
按热度按时间ego6inou1#
NumberValueAccessor负责将每个无效值转换为
null
。这是预期的行为。
prdp8dxp2#
要检查一个值是否为
NaN
,如果可能的话,你应该首先将该值转换为一个数字,然后使用方法Number.isNaN()
,在你的例子中,你可以尝试:zed5wv103#
在GitHub上查看与此相关的Angular问题时,更准确地说是Issue #2962,我找到了一个解决方案,利用HTML5的
badInput
属性,该属性存在于某些类型的<input>
元素中,包括number
。我写了一个自定义的验证器指令,类似于Angular Issue #2962的评论中所示的指令,但与此不同的是,我写的指令必须显式应用,目前只能应用于
<input type="number">
字段(但如果需要,通过更改指令的selector
,这应该很容易更改)。bad-input-validator.directive.ts
这可能会以某种方式得到改善,但现在它做了我需要做的。当我将
appBadInputValidator
应用于<input type="number">
元素,并输入一个将解析为NaN
的值时,FormControl
和FormGroup
被标记为无效,并且提交按钮被正确禁用。该指令的工作方式类似于Angular.JS的表单验证,它跟踪
badInput
,但这种行为目前在Angular中不存在,至少在版本16.2.6中是这样。非常感谢amc 1804在GitHub上发布解决方案。