Using Angular version 11.1.2
So, in my project there is a simple input field styled using angular material to enter name before redirecting to a new page, here are some validators that I've set in Form control:
- required
- minlength of 5
- maxlength of 25
- after all above validators are checked; through an api request at(
/api/check/:name) it returns true (if name already exists) and false (if name doesnot not exists) -- (this one is not currently implemented in code and I think a custom async validators must be used)
I've also set autofocus on the input field; as soon as the component is loaded the focus goes directly to this input field. Also, for showing that username is valid or not there are some mat-icon as matSuffix ✔ for valid username and ❌ for invalid form input, also there is mat-progress-spinner for showing async validator is working.
Here is my component.html:
<mat-form-field appearance="outline" [ngStyle]="{ 'display': 'inline', 'font-size': '11pt' }">
<mat-label class="inut-label">Enter your Username</mat-label>
<input type="text" matInput placeholder="Eg: John123, Robo@123" [formControl]="username" autocomplete="off" autofocus required>
<div class="form-condition" matSuffix>
<mat-progress-spinner *ngIf="showSpinner" diameter="24" mode="indeterminate" color="accent"></mat-progress-spinner>
<!-- form is incorrect icon -->
<mat-icon *ngIf="username.invalid && !showSpinner" color="warn">clear</mat-icon>
<!-- form is correct icon -->
<mat-icon *ngIf="username.valid && !showSpinner" [ngStyle]="{ 'color': 'green' }">done</mat-icon>
</div>
<mat-error *ngIf="username.invalid">{{getErrorMessage()}}</mat-error>
</mat-form-field>
<button mat-raised-button color="primary" *ngIf="username.valid" class="form-login" (click)="navigateToUserWindow()">
<mat-icon>login</mat-icon>
<span> Login</span>
</button>
component.ts:
export class HomeComponent implements OnInit {
username = new FormControl(null, [
Validators.required,
Validators.minLength(5),
Validators.maxLength(25)
]);
showSpinner = false;
constructor(private route: Router) {}
ngOnInit(): void {
this.username.markAsPristine();
}
getErrorMessage(): string {
if (this.username.hasError('required') && this.username.dirty) {
return 'You cannot leave the username empty!';
} else if (this.username.hasError('minlength') && this.username.dirty) {
return 'Username must be at least 5 letters long!';
} else if (this.username.hasError('maxlength') && this.username.dirty) {
return 'Username must be atmost of 25 letters long!';
}
return '';
}
navigateToUserWindow(): void {
this.route.navigate(['user']);
}
}
here is the screenshot
Since, the login button will only appear if the form is valid. I want following things to work:
- On component init since autofocus works I want to hide ❌ icon.
- If validators are invoked when typing inside input show the error message as well as the respective icon representing for valid or invalid. Since, I've seen some examples and these validators show error only work when user remove focus outside of the input.
- I want to show one icon at a time so if async validator are busy show spinner when it's done then show whether form is valid or invalid.
Main problem arises when suppose on first input after autofocus user enters correct value for username and then validator are invoked for some reason this is only reflected by ❌ toggling but no appropriate message is displayed (this only happens when user removes the focus on error and then types again, then only error messages changes dynamically). Currently I'm bit confused about these properties like dirty, touched, untouched, pristine etc. and how can I use them properly according to this particular use case.
