Angular NgForm: reset exact form filed value does not make it valid

孤者浪人 提交于 2019-12-22 08:26:10

问题


I have a form on a component's template:

<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>

And here is my component's submit handler:

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

It works and on login error (passing some random values) I see

Question. How can I reset exact fileld on the Form and make it truly pristine and untouched? So it should be valid without marking it with red "invalid" border on the UI.

Right after loginForm.controls.password.reset() I see that loginForm.controls.password.touched is false and loginForm.controls.password.pristine is true, but I see also that loginForm.controls.password.status is "INVALID". If I hack it and directly assign the "VALID" value to the status property, the red invalid border disappeares, but it breaks lost-focus invalidation in case I focus on that filed and then go away without any input. There should be a legal way to reset form filed and make it valid in the same time.


回答1:


This seems to be a known issue. According to this the error state is calculated like:

isInvalid && (isTouched || isSubmitted)

So when you have submitted your form, the isSubmitted flag is set to true, thus the condition is fulfilled and your field is shown as red. There are some workarounds, if you were to reset the whole form, you could use resetForm instead, but here you only want to reset one field, so...

There is an suggestion to use 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);
  }
}

and declare a ErrorStateMatcher in your TS:

matcher = new MyErrorStateMatcher();

Seems to work: StackBlitz




回答2:


You can make use of markAs existing functions

Something like this

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

These are actual API functions for when you want to enforce a particular state and don’t want to depend entirely on Angular decision of what should the be the state of the field

Check here how to better use the updateValueAndValidity method



来源:https://stackoverflow.com/questions/48026810/angular-ngform-reset-exact-form-filed-value-does-not-make-it-valid

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!