Angular Material封装mat-error为自定义组件后显示异常如何解决
问题原因
- Angular Material 的
mat-form-field仅会识别直接子级的mat-error元素,来应用内置的错误显示逻辑和样式定位规则。将mat-error嵌套在自定义组件内部后,mat-form-field无法识别到深层的mat-error节点,不会触发正确的展示逻辑。 - 自定义组件默认会生成额外的宿主 DOM 节点(
<app-mat-error-too-long>),破坏了mat-form-field期望的DOM结构,进而导致样式错位。
修复方案
推荐方案:改为属性型组件,消除多余宿主层
该方案改动最小,完全贴合Angular Material的原生结构规则,无兼容性问题:
- 调整自定义组件的配置与模板:
import { Component, Input } from '@angular/core'; import { AbstractControl } from '@angular/forms'; @Component({ // 改为属性选择器 selector: '[appMatErrorTooLong]', // 模板去掉外层mat-error标签,直接写提示内容 template: ` <span>Input too long</span> <span> </span> <span>{{ctrl.getError('maxlength').actualLength}}/{{ctrl.getError('maxlength').requiredLength}}</span> `, styleUrls: ['./mat-error-too-long.component.scss'], }) export class MatErrorTooLongComponent { @Input() ctrl: AbstractControl }
- 父组件调用时,直接将属性绑定到原生
mat-error标签上,保证mat-error是mat-form-field的直接子节点:
<form [formGroup]="form"> <mat-form-field> <input matInput formControlName="title" placeholder="Title" required /> <mat-error *ngIf="form.controls.title.hasError('maxlength')" appMatErrorTooLong [ctrl]="form.controls.title"></mat-error> </mat-form-field> </form>
可选方案:不修改调用方式,给自定义组件添加mat-error宿主属性
如果不想调整父组件的调用代码,可以给自定义组件配置宿主属性,让宿主节点本身被识别为mat-error:
- 调整自定义组件配置:
import { Component, Input, Optional } from '@angular/core'; import { AbstractControl } from '@angular/forms'; import { MatFormField } from '@angular/material/form-field'; @Component({ selector: 'app-mat-error-too-long', template: ` <span>Input too long</span> <span> </span> <span>{{ctrl.getError('maxlength').actualLength}}/{{ctrl.getError('maxlength').requiredLength}}</span> `, // 给宿主节点添加mat-error相关的类与属性 host: { 'class': 'mat-error', 'role': 'alert', 'aria-live': 'polite' }, styleUrls: ['./mat-error-too-long.component.scss'], }) export class MatErrorTooLongComponent { @Input() ctrl: AbstractControl constructor(@Optional() private formField: MatFormField) {} }
- 父组件调用时给自定义组件加上错误状态判断即可:
<form [formGroup]="form"> <mat-form-field> <input matInput formControlName="title" placeholder="Title" required /> <app-mat-error-too-long *ngIf="form.controls.title.hasError('maxlength')" [ctrl]="form.controls.title"></app-mat-error-too-long> </mat-form-field> </form>
内容的提问来源于stack exchange,提问作者LeO
相关产品推荐
相关产品推荐

