为啥使用自定义全局验证器在角度材料 6 的 mat-form 字段中未显示 mat-error

Posted

技术标签:

【中文标题】为啥使用自定义全局验证器在角度材料 6 的 mat-form 字段中未显示 mat-error【英文标题】:Why mat-error not get displayed inside mat-form field in angular material 6 withcustom global validators为什么使用自定义全局验证器在角度材料 6 的 mat-form 字段中未显示 mat-error 【发布时间】:2018-12-29 14:08:12 【问题描述】:

我正在使用角度材料 6,当在 mat-form-field 之后移动到正确显示的 mat-error 时,mat-form-field mat-error is not displayed 内部有一个变化。

不工作的代码:

 <mat-form-field>
<input matInput type="time" formControlName="ToTime"/> <mat-error *ngIf="DaterForm.get('ToTime').hasError('InValidToTime')">FromTime Should be less than ToTime if choose a same date</mat-error>
     </mat-form-field>

工作正常:

 <input matInput type="time" formControlName="ToTime"/> </mat-form-field>
 <mat-error *ngIf="DaterForm.get('ToTime').hasError('InValidToTime')">FromTime Should be less than ToTime if choose a same date</mat-error>

有人解释了为什么在该控件中不起作用。

现场演示: stackblitz

【问题讨论】:

【参考方案1】:

是的,mat-error 默认不显示。它仅在输入为touched 时显示。

但是,幸运的是,您可以使用绑定到 mat-input 元素的 errorStateMatcher 输入属性覆盖此行为。

添加此功能的pull request。

用法:

<mat-form-field>
    <input matInput [errorStateMatcher]="matcher" [matDatepicker]="picker" placeholder="Choose a Start date" 
    formControlName="FromDate"
      [min]="minFromDate" 
           [max]="maxToDate" >
    <mat-datepicker-toggle matSuffix [for]="picker" ></mat-datepicker-toggle>
    <mat-datepicker #picker></mat-datepicker>
    <mat-error >Please provide a valid Fromdate</mat-error> 
  </mat-form-field> 

所以你必须以这种方式在你的代码中实现ErrorStateMatcher

export class MyErrorStateMatcher implements ErrorStateMatcher 
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean 
    const isSubmitted = form && form.submitted;
    return (control && control.invalid);
  

并在您的组件中为ErrorStateMatcher 类添加一个新对象matcher,它将作为[errorStateMatcher]="matcher" 的值

matcher = new MyErrorStateMatcher();

我还在你的分叉stackblitz中添加了相同的代码

建议

您无需为mat-error 提供ngIf 条件,指定您的formControlName。将根据它所在的mat-form-field 自动考虑它。

【讨论】:

感谢您的宝贵建议,有没有其他方法可以执行相同的行为?但是在您的解决方案中,您已经删除了 mat error 中的 NgIf 指令,我不想显示错误消息默认当表单被触摸时不满足特定条件需要显示错误消息,例如)&lt;input matInput [errorStateMatcher]="matcher" type="time" formControlName="ToTime" &gt; &lt;mat-error *ngIf="DaterForm.get('ToTime').hasError('InValidToTime')"&gt;FromTime Should be less than ToTime if choose a same date&lt;/mat-error&gt; &lt;/mat-form-field&gt; *ngIf 中没有任何具体内容。您正在做与mat-error 相同的事情。这是多余的。如果你不想在被触摸之前显示错误,那是mat-error 默认做的。 好的,我已经删除了*ngIF,并使用errorstateMatcher 和没有ErrorstateMatcher 进行了尝试,那么为什么To Time: &lt;mat-form-field&gt; &lt;input matInput [errorStateMatcher]="matcher" type="time" formControlName="ToTime" &gt; &lt;mat-error &gt;FromTime Should be less than ToTime if choose a same date&lt;/mat-error&gt; &lt;/mat-form-field&gt; 不起作用。这是一个分叉的:stackblitz.com/edit/angular-customvalidator-gbcjep?file=app/… 这可能是因为你没有提到你的时间Validators 反对你的toTime 表单控件作为formGroup 的一部分。 mat-error 不会认识全球的Validators。如果您希望 mat-error 显示 mat-error,则应针对每个 formControl 明确指定 Validators *ngIf="DaterForm.get('ToTime').hasError('InValidToTime')" 永远不会为真,因为您的错误永远不会绑定到ToTime 表单控件。【参考方案2】:

我找到了一个非常简单的解决方案,无需覆盖 ErrorStateMatcher 类,只需在 app.module.ts 中导入即可

1- 导入库:

import  ErrorStateMatcher, ShowOnDirtyErrorStateMatcher  from '@angular/material/core'; 

2- 添加到提供者,例如:

@NgModule(
  providers: [
    AuthService,
    UserService,
     provide: ErrorStateMatcher, useClass: ShowOnDirtyErrorStateMatcher 
  ],
)

重新提供应用程序。

Reza Taba 于 2021 年 1 月 2 日更新

上述简短解决方案存在问题:如果用户在触摸(模糊)后将该字段留空,则不会显示必需错误。

请参阅my solution 以获取修复。

【讨论】:

不正确。肮脏与原始相反。 get dirty(): boolean return !this.pristine; 触摸只是它是否有焦点(通过标签或使用鼠标/触摸)。并且某些东西可能会以编程方式变脏而不会被触及。 这里的来源有助于确保您的假设是正确的。是的,这可能会令人困惑! github.com/angular/angular/blob/… 虽然 sherif 提出的建议是正确的,但对于延迟加载的模块,这不起作用。有一个未解决的问题:github.com/angular/components/issues/10084【参考方案3】:

全局,在输入或触摸时显示 mat-error: 与提供的解决方案不同,此方法将处理所有 mat-errors,而无需对每个输入字段应用匹配器。

1- 创建 touched-error-state.matcher.ts 文件:

import FormControl, FormGroupDirective, NgForm  from '@angular/forms';
import ErrorStateMatcher from '@angular/material/core';

export class TouchedErrorStateMatcher implements ErrorStateMatcher 
    isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean 
        return !!(control && control.invalid && (control.dirty || control.touched));
    

2- 在 app.module 中导入:

import  ErrorStateMatcher  from '@angular/material/core';
import  TouchedErrorStateMatcher  from './your-folder-path/touched-error-state.matcher';

3- 现在将其提供给提供者:

@NgModule(
  providers: [
    AuthService,
    UserService,
     provide: ErrorStateMatcher, useClass: TouchedErrorStateMatcher 
  ],
)

4- 重新提供应用程序。

【讨论】:

以上是关于为啥使用自定义全局验证器在角度材料 6 的 mat-form 字段中未显示 mat-error的主要内容,如果未能解决你的问题,请参考以下文章

角度材料 - mat-error 不显示输入字段的错误消息

角度材料步进更改图标颜色

无法在角度 6 中实现材料视图低于错误

角度材料 MatButtonToggle 中的中心文本

为啥我不能在自定义字段验证器中返回全局消息键?

角度材料单选按钮默认选中不验证表单