Reputation: 20734
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.
Upvotes: 4
Views: 2444
Reputation: 73337
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
Upvotes: 4
Reputation: 3243
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
Upvotes: 0