【问题标题】:Both mat-error show when only one condition is true当只有一个条件为真时,两个 mat-error 都显示
【发布时间】:2019-11-14 11:56:55
【问题描述】:

当只出现一个错误时,两个 mat-error 都会显示。

我正在尝试使用 mat-error 制作自定义验证器。当每个电子邮件的输入和确认密码都具有 hasError('') 的真值时,它们都是红色的。

我认为我的 MyErrorStateMatcher 类逻辑在某种程度上是错误的。请帮忙!我已经尝试了我能做的任何事情。提前谢谢!

Image

如图所示。当confirmPassword 抛出错误时,email 字段也是红色的。


我的 ErrorStateMatcher:

export class MyErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    const invalidCtrl = !!(control && control.invalid && (control.dirty || control.touched));
    const invalidParent = !!(control && (control.parent.hasError('notTheSame') || control.parent.hasError('emailUsed')));

    return ((invalidCtrl || invalidParent));
  }
}

HTML:(专注于电子邮件和 confimPassword)

<form [formGroup]="signupForm" (ngSubmit)="signup(signupForm)">
        <mat-form-field style="width: 100%;">
          <input matInput formControlName="email" placeholder="Email address" type="email" [errorStateMatcher]="matcher" required>
          <mat-error *ngIf="signupForm.controls.email.hasError('required')">Email required!</mat-error>
          <mat-error *ngIf="signupForm.controls.email.hasError('email')">Email invalid!</mat-error>
          <mat-error *ngIf="signupForm.hasError('emailUsed')">This email already exists!</mat-error>
        </mat-form-field>
        <mat-form-field style="width: 100%;">
          <input matInput formControlName="username" placeholder="User name" (blur)="signupForm.value.username != null ? isValidUsername(signupForm.value.username) : ''" required />
          <mat-error>Please enter your new username!</mat-error>
          <mat-error *ngIf="usernameInvalid">Username already exists!</mat-error>
        </mat-form-field>
        <mat-form-field style="width: 100%;">
          <input matInput formControlName="password" placeholder="New password" [type]="show ? 'text' : 'password'" required />
          <mat-icon matSuffix (click)="show = !show" style="cursor: pointer;">{{show ? 'visibility' : 'visibility_off'}}</mat-icon>
          <mat-error>Please enter your password!</mat-error>
        </mat-form-field>
        <mat-form-field style="width: 100%;">
          <input matInput formControlName="confirmPassword" placeholder="Confirm password" type="password" [errorStateMatcher]="matcher" required>
          <mat-error *ngIf="signupForm.controls.confirmPassword.hasError('required')">Please confirm your password!</mat-error>
          <mat-error *ngIf="signupForm.hasError('notTheSame') && signupForm.value.confirmPassword != ''">Password is not the same!</mat-error>
        </mat-form-field>
        <br>
      <button mat-raised-button class="sessionBtn" color="primary" [disabled]="signupForm.invalid">Submit!</button>
</form>

TS:

signupForm = new FormGroup({
    firstName: new FormControl(),
    lastName: new FormControl(),
    email: new FormControl('', [
      Validators.required,
      Validators.email
    ]),
    username: new FormControl(),
    password: new FormControl('', [
      Validators.required
    ]),
    confirmPassword: new FormControl('', [
      Validators.required
    ])
  }, { validators: [this.checkPassword, this.checkExistingEmail] });
  matcher = new MyErrorStateMatcher();

/////////Custom validator////////

  checkPassword(signupForm: FormGroup) {
    let password = signupForm.value.password;
    let confirmPassword = signupForm.value.confirmPassword;

    return password === confirmPassword ? null : { notTheSame: true };
  }

  checkExistingEmail(signupForm: FormGroup) {
    let inputEmail = signupForm.value.email;
    let dbEmail = "test@test.com";

    return inputEmail !== dbEmail ? null: { emailUsed: true };
  }

输入电子邮件和输入确认密码发生错误,两者都有[errorStateMatcher]="matcher"

【问题讨论】:

  • 除了@G。 Tranter 回答另一种方法是您可以使用模式验证器并通过正则表达式来检查重复的电子邮件
  • 你必须明白有一个customErrorMatches的目的。看到这个很棒的链接itnext.io/…&lt;mat-error&gt; 仅显示&lt;mat-form-field&gt; 内的输入是否无效。使用 customErrorMatches 您可以说 mat-error 以不同的状态显示(在链接中显示当表单有错误并且控件脏时 - 尽管控件是有效的!)。在您的代码中,如果表单无效,则所有具有[errorStateMatcher]="matcher" 的输入都将无效,因此请删除电子邮件输入中的[errorStateMatcher]
  • @Eliseo 删除它们可能是个好主意,但我需要它稍后为电子邮件本身制作一个自定义验证器,以检查数据库中的重复电子邮件。有没有办法将所有自定义验证器合并到一个 errorStateMatcher 中?
  • 如果你的checkExistingEmail只依赖email,把validator放在email里(不在form里),如果依赖其他字段,你可以使用两个不同的customErrorMatcher
  • 你的意思是这样做?:email: new FormControl('', [ Validators.required, Validators.email, this.checkExistingEmail &lt;== put this here? ]) 制作 2 个不同的 customErrorMatcher 是一个好习惯。如果我有很多验证器怎么办?

标签: angular typescript angular-material


【解决方案1】:

创建一个 customErrorMatcher

好吧,如果我们想在input 有效时在&lt;mat-form-field&gt; 中显示错误,我们使用customErrorMatcher。

这是一个类

class CrossFieldErrorMatcher implements ErrorStateMatcher {
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    //when we want to show the error
    return true 
    //when we want not show the error
    return false
  }
}

通常我们的组件中有

  errorMatcher=new CrossFieldErrorMatcher()
  //and the .html
  <mat-form-field>
    <input matInput formControlName='verifyPassword' 
        [errorStateMatcher]="errorMatcher">
    <mat-error *ngIf="....">
      Passwords do not match!
    </mat-error>
  </mat-form-field>

好吧,我们稍微改变一下,在 customErrorMatcher 中添加一个构造函数

class CrossFieldErrorMatcher implements ErrorStateMatcher {
  constructor(private name:string){}  //<--add a constructor
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    //when we want to show the error, but we can use "name"
    return true 
    //when we want not show the error
    return false
  }
}

那么,我们的组件就变成了

  errorMatcher(name:string)
  {
    return new CrossFieldErrorMatcher(name);
  }

  //and the .html
  <mat-form-field>
    <input matInput formControlName='verifyPassword' 
        [errorStateMatcher]="errorMatcher('password')">
    <mat-error *ngIf="....">
      Passwords do not match!
    </mat-error>
  </mat-form-field>

【讨论】:

    【解决方案2】:

    电子邮件地址字段显示错误,因为错误状态匹配器检查父级(即表单)错误,因为密码字段不匹配。您需要为电子邮件字段和密码字段使用不同的错误状态匹配器,因为条件不同 - 如果密码字段不匹配,电子邮件不需要出错。

    【讨论】:

    • 有没有办法将它们与一个errorStateMatcher结合起来?
    • 不是我能看到的“好”方式。您总是可以破解 - 就像将“名称”属性添加到您可以在匹配器中签入的控件。例如。 signupForm['confirmPassword']['name'] = 'confirmPassword' 和匹配器中的 return (invalidCtrl || (control['name'] === 'confirmPassword' &amp;&amp; invalidParent))。或者(更好一点)您可以创建相同匹配器类的单独实例,并使用构造函数向实例添加名称属性。但是 IMO,一刀切的方法更难阅读/理解,更难维护,更容易出现错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-06
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-07
    相关资源
    最近更新 更多