typescript 相对于NaN值,< input type="number">

pod7payv  于 2023-10-22  发布在  TypeScript
关注(0)|答案(3)|浏览(125)

我正在使用Angular Reactive表单创建一个表单,出于用户体验的原因,当在<input type="number">字段中插入某些无效值时,我试图禁用表单的提交,例如负数或非整数。
问题是,当我插入一个值时,即使<input type="number">允许,通常也会计算为NaN,例如,单独的字母e,后面没有数字的减号或加号,甚至是一个太大而无法用TypeScript number表示的数字,而是在通过control.valuecontrol.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
}
ego6inou

ego6inou1#

NumberValueAccessor负责将每个无效值转换为null
这是预期的行为。

prdp8dxp

prdp8dxp2#

要检查一个值是否为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
      }
    }
  }
zed5wv10

zed5wv103#

在GitHub上查看与此相关的Angular问题时,更准确地说是Issue #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的值时,FormControlFormGroup被标记为无效,并且提交按钮被正确禁用。
该指令的工作方式类似于Angular.JS的表单验证,它跟踪badInput,但这种行为目前在Angular中不存在,至少在版本16.2.6中是这样。
非常感谢amc 1804在GitHub上发布解决方案。

相关问题