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

Angular Material自定义输入验证消息在Mat-Stepper中不显示求助

解决自定义表单控件在Mat-Stepper中调用markAllAsTouched()后错误消息不显示的问题

问题原因

基于ControlValueAccessor实现的自定义控件,未同步父表单的touched状态。当调用form.markAllAsTouched()时,父表单控件状态更新,但自定义控件内部的触摸状态未被触发,导致MatFormField无法识别控件已触摸,错误消息仅在手动触摸控件后才显示。

解决方案

需要在自定义控件中同步父控件的touched状态,确保onTouched回调被正确触发,具体步骤如下:

1. 跟踪自定义控件的触摸状态

在组件类中添加touched属性,并实现markAsTouched()方法统一处理状态更新和回调触发:

touched = false;

markAsTouched(): void {
  if (!this.touched) {
    this.touched = true;
    this.onTouched();
  }
}

2. 订阅父控件的状态变化

在ngOnInit中监听父控件的状态变化,当父控件被标记为touched时,同步触发自身的markAsTouched()方法:

ngOnInit(): void {
  this.ngControl.statusChanges?.subscribe(() => {
    if (this.ngControl.touched && !this.touched) {
      this.markAsTouched();
    }
  });
}

3. 绑定模板事件

确保模板中的输入框绑定blur事件到onBlur()方法(内部调用markAsTouched()):

<input 
  type="text" 
  [(ngModel)]="value" 
  (input)="onInput($event)" 
  (blur)="onBlur()"
>

对应的组件方法:

onBlur(): void {
  this.markAsTouched();
}

完整自定义控件示例代码

import { Component, OnInit, Self } from '@angular/core';
import { ControlValueAccessor, NgControl } from '@angular/forms';

@Component({
  selector: 'app-phone-input',
  templateUrl: './phone-input.component.html'
})
export class PhoneInputComponent implements ControlValueAccessor, OnInit {
  value: string = '';
  touched = false;

  onChange = (value: string) => {};
  onTouched = () => {};

  constructor(@Self() public ngControl: NgControl) {
    this.ngControl.valueAccessor = this;
  }

  ngOnInit(): void {
    this.ngControl.statusChanges?.subscribe(() => {
      if (this.ngControl.touched && !this.touched) {
        this.markAsTouched();
      }
    });
  }

  writeValue(value: string): void {
    this.value = value || '';
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

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

  markAsTouched(): void {
    if (!this.touched) {
      this.touched = true;
      this.onTouched();
    }
  }

  onBlur(): void {
    this.markAsTouched();
  }

  onInput(event: Event): void {
    const inputValue = (event.target as HTMLInputElement).value;
    this.onChange(inputValue);
  }
}

效果验证

修改完成后,调用this.form.markAllAsTouched()时,自定义控件会同步更新触摸状态,Mat-Stepper中的错误消息会立即显示,无需手动触摸控件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 08:45:29