Step 1. Create an angular project with the below command.
ng new angular-material-forms-username-availability
Step 2. After successful creation of the angular app, change the file directory to project-name. “cd angular-material-forms-username-availability”
Open the project in vs code using “code .” in terminal or open with vs code. Then run the project using “ng serve” in the terminal. Open project in chrome using
localhost:4200
Step 3. Open the app component in vs code and remove the content which is created by angular CLI while creating the app.
For Adding angular material using the command
ng add @angular/material
Step 4. Select theme, Am selecting Indigo/Pink,
and click the below items as “yes”.
- Set up global Angular Material typography styles? Am selecting
y
- Set up browser animations for Angular Material? (Y/n) Select ‘y’.
Step 5. Created Shared Module in the libs folder using “ng generate module shared”. And import, export material modules in “shared.module.ts”. And also add in the app.module.ts
Step 6. Create the Signup component in the apps/component folder. And add the signup component in router and path as signup
.
Step 7. Add “ReactiveFormsModule”, and “FormsModule” in app.module.ts as below.
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
SignupComponent
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
FormsModule,
ReactiveFormsModule,
SharedModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Step 8. Open “signup.component.ts”, then add “formbuilder ” as a dependency in the constructor. Create a form variable above the constructor.
import { FormArray, FormBuilder, FormGroup, Validators } from ‘@angular/forms’;public form:FormGroup;constructor(private fb:FormBuilder) { }ngOnInit(): void { }
Step 9. Create formInit method to initialize the form and call the method from either constructor or ngOnInit.
constructor(private fb:FormBuilder) {
this.formInit()
}
ngOnInit(): void { }private formInit(){
}
Step 10. And create a form group using form builder and add controls in that same form. Form Controls like “firstName”, “secondName”, “email”, “username”, “password”, and “mobile”.
private formInit(){
this.form = this.fb.group({
firstName: [‘’,[Validators.required]],
lastName: [‘’,[Validators.required]],
username: [‘’,[Validators.required]],
email: [‘’,[Validators.required]],
password: [‘’,[Validators.required]],
});
}
Step 11. After successfully following the above points. Add Html in signup.component.html related to form step by step.
- Add div and form tag in HTML file.
<div class=”container”>
<form class=”form shadow m-3 p-3" [formGroup]=”form” (ngSubmit)=”submitForm()”>
<h1>Sign Up Form</h1>
</form>
</div>
- Increase code by one form control and add validate message also.
<div class=”container”>
<form class=”form shadow m-3 p-3" [formGroup]=”form” (ngSubmit)=”submitForm()”>
<h1>Sign Up Form</h1>
<div class=”row mt-3">
<mat-form-field class=”col-md-6">
<mat-label>First Name</mat-label>
<input matInput formControlName=”firstName” placeholder=”Enter First Name”>
</mat-form-field>
</div>
</form>
</div>
- Add all the controls and form validation messages.
<div class="container">
<form class="form shadow m-3 p-3" [formGroup]="form" (ngSubmit)="submitForm()">
<h1>Sign Up Form</h1>
<div class="row mt-3">
<mat-form-field class="col-md-6">
<mat-label>First Name</mat-label>
<input matInput formControlName="firstName" placeholder="Enter First Name">
<mat-error *ngIf="this.form.controls.firstName.hasError('required')">
First Name is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
<div class="row mt-3">
<mat-form-field class="col-md-6">
<mat-label>Last Name</mat-label>
<input matInput formControlName="lastName" placeholder="Enter Last Name">
<mat-error *ngIf="this.form.controls.lastName.hasError('required')">
Last Name is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
<div class="row mt-3">
<mat-form-field class="col-md-6">
<mat-label>User Name</mat-label>
<input matInput formControlName="username" placeholder="Enter Username">
<mat-error *ngIf="this.form.controls.username.hasError('required')">
Username is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
<div class="row mt-3">
<mat-form-field class="col-md-6">
<mat-label>Email</mat-label>
<input matInput formControlName="email" placeholder="Enter Email">
<mat-error *ngIf="this.form.controls.email.hasError('required')">
Email <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
<div class="row mt-3">
<mat-form-field class="col-md-6">
<mat-label>Password</mat-label>
<input type="password" matInput formControlName="password" placeholder="Enter Password">
<mat-error *ngIf="this.form.controls.password.hasError('required')">
Password is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
<div class="row mt-3">
<button type="submit" mat-raised-button color="primary" class="m-2" style="width: 100px;" [disabled]="!form.valid">Submit Form</button>
<button type="button" mat-raised-button color="warn" class="m-2" style="width: 100px;" (click)="form.reset()">Reset</button>
</div>
</form>
</div>
Step 12. After successfully adding the Html code and checking the changes in the browser. Add the submit method in signup.component.ts
public submitForm(){
console.log(this.form);
console.log(this.form.getRawValue())
}
Step 13. Test the form by giving all the forms and clicking on submit. You can able to see the values in the console.
Step 14. And if you did not give values in the form you can able to see the error messages.
Step 15. For checking username and email availability we need to create verifyUsernameOrEmail(fieldName) method.
public verifyUsernameOrEmail(fieldName){
const field = this.form.get(fieldName);
if(field.valid){
console.log(field.value)
}
}
Step 16. After that add below two form value changes listeners inside ngOnInit() as mentioned below and also call the above method.
this.form
.get('username')
.valueChanges
.subscribe( (value) => {
this.verifyUsernameOrEmail('username');
});this.form
.get('email')
.valueChanges
.subscribe( (value) => {
this.verifyUsernameOrEmail('email');
});
Step 17. Create a user service file under the app/apis folder and add it as a dependency in signup.component.ts.
constructor(private fb:FormBuilder, private api:UserServiceService) {
this.formInit();
}
To generate a service file enter the command in the terminal as below.
ng generate service user-service
Step 18. Add the verifyUsernameOrEmail(filter?) method in the service file and add the get endpoint for checking the availability of username or email like below.
constructor(private http:HttpClient) { }public verifyUsernameOrEmail(filter){
let params = new HttpParams();
if(filter){
if(filter.username){
params = params.append('username', filter.username);
}
if(filter.email){
params = params.append('email', filter.email);
}
}return this.http.get('http://localhost:3000/public/user/availability',{params})
}
Step 19. Call the service method from the signup component inside of the verifyUsernameOrEmail() like below and also test the service by changing username or email.
public verifyUsernameOrEmail(fieldName){
const field = this.form.get(fieldName);
if(field.valid){
const filter = {}
filter[fieldName] = field.value;
this.api.verifyUsernameOrEmail(filter).subscribe((res: any )=> {
console.log(res.availability)
},
error=>{
console.log(error)
})
}
}
Step 20. After checking the console logs add the logic to display custom validation errors in the UI as below.
const filter = {}
filter[fieldName] = field.value;
this.api.verifyUsernameOrEmail(filter).subscribe((res: any )=> {
if(res?.availability){
const message = fieldName === 'email' ? 'Email already Exists.' : 'Username already Exists.'
fieldName === 'email' ?
field.setErrors({ inValidEmail: true, message}) :
field.setErrors({ inValidUserName: true, message})
}
else{
field.setErrors(null);
fieldName === 'email' ?
field.setValidators([Validators.required,Validators.email]) :
field.setValidators([Validators.required, Validators.minLength(4),Validators.maxLength(20)])
}
Step 21. As per the above diagram if the username is there am setting Errors as Invalid Username is true else am setting it as null, adding existing validators to the field, and also using similar logic for email.
To display error messages in Html you need to add the below lines of code to the existing code.
<div class="row mt-3">
<mat-form-field class="col-md-6" appearance="outline">
<mat-label>User Name</mat-label>
<input matInput formControlName="username" placeholder="Enter Username">
<mat-error *ngIf="this.form.controls.username.hasError('required')">
Username is <strong>required</strong>
</mat-error>
<mat-error *ngIf="this.form.controls.username?.hasError('inValidUserName')">
{{form.controls['username'].errors?.message}}
</mat-error>
</mat-form-field>
</div>
<div class="row mt-3" z>
<mat-form-field class="col-md-6" appearance="outline">
<mat-label>Email</mat-label>
<input matInput formControlName="email" placeholder="Enter Email">
<mat-error *ngIf="this.form.controls.email.hasError('required')">
Email <strong>required</strong>
</mat-error>
<mat-error *ngIf="this.form.controls.email?.hasError('inValidEmail')">
{{form.controls['email'].errors?.message}}
</mat-error>
</mat-form-field>
</div>
To test the output by running the project, see the output by opening URL(localhost:4200/signup) in browser parallelly run backend also by using npm run dev command.
Output Screens:
Screen #1(All Errors)
Screen #2 (Username & Email already exists)
Screen #3(If username and email id not exists)
Source Code
Frontend
GitHub: mryenagandula/angular-material-forms-username-availability
Backend
GitHub: mryenagandula/Letstalk-Backend
Live Backend URI: https://letstalk-be.herokuapp.com/
Stack blitz Project Preview:
https://stackblitz.com/edit/github-angular-material-forms-username-availability
Thanks for reading my article, please share your feedback, claps, and comments. In that way, it will have helped me to improve my articles in the future. Please share my story with your near and dear, also follow and subscribe to the medium.