Angular NgForm:重置确切的表单字段值不会使其有效

Posted

技术标签:

【中文标题】Angular NgForm:重置确切的表单字段值不会使其有效【英文标题】:Angular NgForm: reset exact form filed value does not make it valid 【发布时间】:2018-06-10 03:25:39 【问题描述】:

我在组件的模板上有一个表单:

<form (ngSubmit)="submitLogin(loginForm)" #loginForm="ngForm">
  <mat-input-container>
    <input matInput [placeholder]="'User Name'" ngModel name="username" autofocus required>
  </mat-input-container>
  <br>
  <mat-input-container>
    <input matInput [placeholder]="'Password'" ngModel type="password" name="password" required>
  </mat-input-container>
  <br>
  <button [disabled]="loginForm.invalid" mat-raised-button type="submit">
    Login
  </button>
</form>

这是我的组件的提交处理程序:

public submitLogin(loginForm: NgForm) 
  return this.authService.login(loginForm.value)
    .subscribe(
      res => this.router.navigate(['/customers']),
      error => loginForm.controls.password.reset() // this place!
    );

我看到了它的工作原理和登录错误(传递了一些随机值)

问题。如何重置表单上的确切字段并使其真正原始且未受影响?所以它应该是有效的,而不用在 UI 上用红色的“无效”边框标记它。

loginForm.controls.password.reset() 之后,我看到loginForm.controls.password.touchedfalseloginForm.controls.password.pristinetrue,但我也看到loginForm.controls.password.status 是“无效”。如果我破解它并直接将“VALID”值分配给status 属性,红色无效边框会消失,但如果我专注于该字段然后消失,它会破坏失去焦点的失效没有任何输入。应该有一种合法的方式来重置提交的表单并使其同时生效。

【问题讨论】:

【参考方案1】:

您可以利用markAs现有功能

像这样的

this.loginForm.controls.password.reset()
this.loginForm.controls.password.markAsPristine()
this.loginForm.controls.password.markAsUntouched()
this.loginForm.controls.password.updateValueAndValidity()

这些是实际的 API 函数,用于当您想要强制执行特定状态并且不想完全依赖 Angular 来决定该字段的状态应该是什么时

检查here如何更好地使用updateValueAndValidity方法

【讨论】:

不幸的是,这并不重要,因为(正如我在问题中提到的)已重置的控件已经原始且未受影响。问题在于它的状态仍然是“无效”... 我已经编辑了我的答案以包括解决您的问题的附加电话。还包括指向 Angular 文档的链接,您可以在其中检查它的使用情况【参考方案2】:

这似乎是一个已知问题。根据 this,错误状态的计算方式如下:

isInvalid && (isTouched || isSubmitted)

因此,当您提交表单时,isSubmitted 标志设置为true,因此满足条件并且您的字段显示为红色。有一些变通方法,如果你要重置整个表单,你可以使用resetForm,但是这里你只想重置一个字段,所以......

有一个suggestion可以使用ErrorStateMatcher

<input matInput 
   [placeholder]="'Password'" 
   ngModel type="password" 
   name="password" required 
   [errorStateMatcher]="matcher">

ErrorStateMatcher:

export class MyErrorStateMatcher implements ErrorStateMatcher 
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean 
    // show errors when touched and invalid
    return (control.invalid && control.touched);
  

并在您的 TS 中声明一个 ErrorStateMatcher:

matcher = new MyErrorStateMatcher();

似乎有效:StackBlitz

【讨论】:

感谢演示和解释!但是丢失焦点事件的失效失效问题仍然存在。我分叉了你的 StackBlitz (link) 以证明我可以通过设置 loginForm.controls.password.setErrors(null) 轻松获得相同的结果(与破坏性设置 loginForm.controls.password.status = "VALID" 相同的方法)。但是当我专注于它时,我需要让这个文件无效,然后不做任何更改。 好吧,我在帖子中首先建议loginForm.controls.password.setErrors(null),但请注意,重置后按钮已启用,因为错误已被删除并且不再需要密码:) 但回到你的问题,你的意思是你想在touched 时显示错误? stackblitz.com/edit/angular-hbq2uv-z3xxvp?file=app/… 是的,您上次的更新问题已经解决,非常感谢! 太好了,很高兴听到!我会相应地更新我的答案:)

以上是关于Angular NgForm:重置确切的表单字段值不会使其有效的主要内容,如果未能解决你的问题,请参考以下文章

尽管 Angular 中的表单已重置,但输入字段仍标记为红色

form.reset()后表单无效 - Angular2

Angular 2 自定义表单输入

我可以在 Angular 4 的同一个组件中使用两个 ngForm 吗?

如何使用 Angular 重置自定义表单控件

Angular:如何重置 matChipList 输入字段和 Google Recaptcha?