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

Angular14中基于Angular Material实现带验证的自定义输入组件

实现Angular Material自定义输入组件并绑定表单验证

完全可以实现你要的效果,只需要让自定义组件对接Angular的表单体系,核心是实现ControlValueAccessor接口,并通过NgControl关联父组件的FormControl,这样父组件设置的验证规则会自动作用到自定义组件,错误提示也能按需展示。

步骤1:自定义组件实现ControlValueAccessor

在自定义输入组件中,注入NgControl来获取父组件的FormControl实例,同时实现ControlValueAccessor的四个方法,让组件能和Angular表单双向绑定:

import { Component, Input } from '@angular/core';
import { ControlValueAccessor, NgControl } from '@angular/forms';
import { MatFormFieldAppearance } from '@angular/material/form-field';

@Component({
  selector: 'app-custom-input',
  templateUrl: './custom-input.component.html',
  styleUrls: ['./custom-input.component.scss'],
})
export class CustomInputComponent implements ControlValueAccessor {
  @Input() label!: string;
  @Input() appearance: MatFormFieldAppearance = 'fill';

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

  constructor(public ngControl: NgControl) {
    // 将当前组件设为NgControl的valueAccessor
    ngControl.valueAccessor = this;
  }

  // 从父表单写入值到组件
  writeValue(value: string): void {}

  // 注册值变化回调(通知父表单值更新)
  registerOnChange(fn: (value: string) => void): void {
    this.onChange = fn;
  }

  // 注册触摸回调(通知父表单组件已被触摸)
  registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }

  // 设置组件禁用状态
  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  // 判断是否需要显示错误
  get hasError(): boolean {
    const control = this.ngControl.control;
    return !!(control && control.invalid && (control.touched || control.dirty));
  }

  // 根据错误类型返回对应提示文本
  get errorMessage(): string {
    const control = this.ngControl.control;
    if (!control) return '';

    if (control.hasError('required')) {
      return `${this.label} 不能为空`;
    }
    if (control.hasError('minlength')) {
      const requiredLen = control.getError('minlength').requiredLength;
      return `${this.label} 长度至少为 ${requiredLen} 个字符`;
    }
    // 可扩展更多错误类型,比如email、maxlength等
    return '';
  }
}

步骤2:自定义组件模板(关联Angular Material Input)

在模板中使用mat-form-field和mat-input,绑定值变化和触摸事件,并通过mat-error显示错误:

<mat-form-field [appearance]="appearance">
  <mat-label>{{ label }}</mat-label>
  <input
    matInput
    [value]="ngControl.control?.value"
    (input)="onChange($event.target.value)"
    (blur)="onTouched()"
    [disabled]="disabled"
  />
  <mat-error *ngIf="hasError">{{ errorMessage }}</mat-error>
</mat-form-field>

步骤3:父组件中使用自定义组件并设置验证规则

在父组件的FormGroup中定义FormControl和验证规则,直接通过formControlName绑定到自定义组件:

父组件TS代码

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  form: FormGroup;

  constructor(private fb: FormBuilder) {
    this.form = this.fb.group({
      username: ['', [Validators.required, Validators.minLength(3)]],
    });
  }

  onSubmit(): void {
    if (this.form.invalid) {
      // 标记所有控件为已触摸,触发错误提示
      this.form.markAllAsTouched();
      return;
    }
    // 处理表单提交逻辑
    console.log(this.form.value);
  }
}

父组件HTML代码

<form [formGroup]="form" (ngSubmit)="onSubmit()">
  <app-custom-input
    formControlName="username"
    label="Username"
  ></app-custom-input>

  <button mat-raised-button color="primary" type="submit">提交</button>
</form>

关键说明

  • 通过NgControl,自定义组件能直接访问父组件设置的FormControl,包括验证规则和错误状态
  • ControlValueAccessor接口是Angular表单与自定义组件通信的标准方式,确保组件支持formControlName/formControl绑定
  • mat-error的显示时机由hasError控制,只有当控件无效且已触摸/修改时才会显示错误提示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 00:45:19