You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular输入框仅允许数字输入:如何显示错误提示?

Angular输入框非数字输入时显示错误提示方案

你的问题核心在于:现有指令会直接过滤掉非数字内容,导致表单控件的值始终是合法数字,因此Validators.pattern无法检测到错误。要解决这个问题,需要在指令中跟踪用户的原始输入,手动给表单控件设置错误状态,再在模板中根据错误状态展示提示。

步骤1:修改OnlyNumberDirective,添加错误状态控制

注入NgControl来访问表单控件实例,在用户输入非数字时设置错误,输入合法数字时清除错误:

import { Directive, ElementRef, forwardRef, HostListener, Renderer2 } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms';

@Directive({
    selector: '[onlyNumber]',
    providers: [{
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => OnlyNumberDirective),
        multi: true
    }]
})
export class OnlyNumberDirective implements ControlValueAccessor {
    private onChange: (val: string) => void;
    private onTouched: () => void;
    private value: string;

    constructor(
        private elementRef: ElementRef,
        private renderer: Renderer2,
        private ngControl: NgControl // 新增:注入表单控件实例
    ) {
    }

    @HostListener('input', ['$event.target.value'])
    onInputChange(value: string) {
        const filteredValue: string = filterValue(value);
        const hasInvalidInput = value !== filteredValue;

        // 根据输入合法性设置/清除错误
        if (hasInvalidInput) {
            this.ngControl.control.setErrors({ invalidNumber: true });
        } else {
            // 仅清除我们设置的错误,保留其他可能的验证错误
            if (this.ngControl.control.errors?.invalidNumber) {
                delete this.ngControl.control.errors.invalidNumber;
                if (Object.keys(this.ngControl.control.errors).length === 0) {
                    this.ngControl.control.setErrors(null);
                }
            }
        }

        this.updateTextInput(filteredValue, this.value !== filteredValue);
    }

    @HostListener('blur')
    onBlur() {
        this.onTouched();
    }

    private updateTextInput(value: string, propagateChange: boolean) {
        this.renderer.setProperty(this.elementRef.nativeElement, 'value', value);
        if (propagateChange) {
            this.onChange(value);
        }
        this.value = value;
    }

    // ControlValueAccessor 接口实现
    registerOnChange(fn: any): void {
        this.onChange = fn;
    }

    registerOnTouched(fn: any): void {
        this.onTouched = fn;
    }

    setDisabledState(isDisabled: boolean): void {
        this.renderer.setProperty(this.elementRef.nativeElement, 'disabled', isDisabled);
    }

    writeValue(value: any): void {
        value = value ? String(value) : '';
        this.updateTextInput(value, false);
    }
}

function filterValue(value): string {
    return value.replace(/[^0-9]*/g, '');
}

步骤2:模板中添加错误提示

模板驱动表单

通过ngModel引用获取控件状态,当控件无效且已交互时显示提示:

<h3>Template Driven Form</h3>
<form #form="ngForm">
  <input 
    name="number" 
    type="text" 
    onlyNumber 
    [(ngModel)]="number"
    #numberInput="ngModel"
    class="form-control"
  />
  <!-- 错误提示 -->
  <div *ngIf="numberInput.invalid && (numberInput.dirty || numberInput.touched)" style="color: red; margin-top: 4px;">
    请输入有效的数字
  </div>
  <p>model value: {{ number }}</p>
  <p>form dirty: {{ form.dirty }}</p>
</form>

响应式表单

通过表单组获取控件状态,同样在控件无效且已交互时显示提示:

<h3>Reactive Form</h3>
<form [formGroup]="formGroup">
  <input 
    formControlName="number" 
    type="text" 
    onlyNumber 
    class="form-control"
  />
  <!-- 错误提示 -->
  <div *ngIf="formGroup.get('number').invalid && (formGroup.get('number').dirty || formGroup.get('number').touched)" style="color: red; margin-top: 4px;">
    请输入有效的数字
  </div>
  <p>model value: {{ formGroup.get('number').value }}</p>
  <p>form dirty: {{ formGroup.dirty }}</p>
</form>

原理说明

  • 当用户输入非数字内容时,原始输入值和过滤后的值不一致,此时给控件设置invalidNumber错误
  • 当用户输入纯数字时,过滤前后值一致,清除invalidNumber错误
  • 模板通过检测控件的invalid状态+dirty/touched状态,确保仅在用户交互后显示错误提示

内容的提问来源于stack exchange,提问作者Sard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 20:44:53