针对 <input type="number">

问题描述 投票:0回答:3

我正在使用 Angular Reactive 表单创建表单,出于用户体验原因,我尝试在

<input type="number">
字段中插入某些无效值(例如负数或非整数)时禁用表单的提交。

问题是,当我插入一个值时,即使

<input type="number">
允许,通常也会计算为
NaN
,例如,单独的字母
e
、后面没有数字的减号或加号,或者即使是太大而无法用 TypeScript
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
}
angular typescript angular-reactive-forms nan angular-custom-validators
3个回答
0
投票

NumberValueAccessor 负责将每个无效值转换为

null

这是预期的行为。


0
投票

要检查某个值是否为

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
      }
    }
  }

0
投票

在 GitHub 上查看与此相关的 Angular 问题时,更准确地说是Issue #2962,我找到了一种解决方法,利用 HTML5 的

badInput
属性存在于某些类型的
<input>
元素(包括
number
)中。

我编写了一个自定义验证器指令,类似于 在 Angular Issue #2962 的评论中显示的指令,但与该指令不同的是,我编写的指令必须显式应用,并且目前只能应用于

<input type="number">
字段(但如果需要,通过更改指令的
selector
应该很容易更改)。

错误输入验证器.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
被标记为无效,并且提交按钮被正确禁用。

非常感谢 GitHub 上的 amc1804 发布解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.