How To Create Reusable Reactive Form in Angular

Pritam Banerjee
5 min readMar 4, 2023

--

To create Angular Reusable Reactive Form we need to some steps to follow the solid Principe and make our code dry. When we build Angular we need to follow best practices but some of the time you need to create your own mechanism to create flexible and salable Angular Reactive Form.

For example if you are creating a login form then there are some situation occur that you need to reuse this form in different components. So how to create a reusable or scalable or flexible reactive form that you can across other components. So lets follow the guideline below and you can create a flexible and reusable Angular Reactive Form which will follow the best practices. We will create a signup form below.

Create an Constant File to Store Form Keys and Constants

First lets create a constant file in the src folder and contact file name is app.constant.ts. Now in the constant file give your signup form key names in this fashion given below.

export const AppConstant = {
forms: {
signup: {
name: {
control: 'name',
label: 'Name'
},
email: {
control: 'email',
label: 'Email'
},
password: {
control: 'password',
label: 'Password'
},
dob: {
control: 'dob',
label: 'Date Of Birth'
},
address: {
control: 'address',
label: 'Address'
},
pincode: {
control: 'pincode',
label: 'Pin Code'
}
},
errors: {
datePicker: {
required: {
message: 'This field is required and date format in mm/dd/yyyy'
},
notRequird: {
message: 'Invalid date Format and date format in mm/dd/yyyy'
},
format: {
message: 'MM/DD/YYYY'
}
}
}
}
}

Create a User Model by using Typescript Interface:

As we have created a constant to manage the form controls and general errors object for datepicker for date of birth field, so in order to define user model we need to create an interface by which we will defined what are the key name will be there in User Model. So create a file name called user.model.ts file and write this below code.

export interface User {
name: string,
email: string,
password: string,
dob: string,
address: string,
pincode: string
}

Create a Common Service

So now we will create a common service by using this following command.

ng g s common

Once the common service is created then we need to create the Signup Form in the common service and we will use root component that AppComponent to build the Angular Reactive Form. We will write this following code to create the form using FormBuilder.

   createSignupForm(): FormGroup {
return this.fb.group({
[AppConstant.forms.signup.name.control]: ['', Validators.required],
[AppConstant.forms.signup.email.control]: ['', Validators.required],
[AppConstant.forms.signup.password.control]: ['', Validators.required],
[AppConstant.forms.signup.dob.control]: [''],
[AppConstant.forms.signup.address.control]: ['', Validators.required],
[AppConstant.forms.signup.pincode.control]: ['', Validators.required]
});
}

Create Reactive Form in the Root Component (App Component):

Now we need to create the reactive form in the root component, so lets create the reactive form in app.component.ts file and reuse the common service form.

export class AppComponent implements OnInit {
signupForm?: FormGroup;

constructor(private commonService: CommonService) { }

get appConstant() {
return AppConstant
}

ngOnInit(): void {
this.createSignupForm();
}

createSignupForm(): void {
this.signupForm = this.commonService.createSignupForm();
}

onSubmit(isValid: boolean, payload: User): void {
if (isValid) {
...Do the Signup Api Call
}
}
}

Once the signup form is created in the app.component.ts file, now we need to write the corresponding html file (app.component.html) in order to bind the signupForm to the view layer.

<form [formGroup]="signupForm" (ngSubmit)="onSubmit(signupForm.valid, signupForm.value)">
<div class="grid pt-3">
<div class="col-12 sm:col-12 md:col-4 lg:col-4 xl:col-4">
<mat-form-field >
<mat-label>{{appConstant.forms.signup.name.label}}</mat-label>
<input type="text" matInput [formControlName]="appConstant.forms.signup.name.control">
<mat-error *ngIf="signupForm.controls[appConstant.forms.signup.name.control].hasError('required')">
This field is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>


<div class="col-12 sm:col-12 md:col-4 lg:col-4 xl:col-4">
<mat-form-field >
<mat-label>{{appConstant.forms.signup.email.label}}</mat-label>
<input type="email" matInput [formControlName]="appConstant.forms.signup.email.control">
<mat-error *ngIf="signupForm.controls[appConstant.forms.signup.email.control].hasError('required')">
This field is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>

<div class="col-12 sm:col-12 md:col-4 lg:col-4 xl:col-4">
<mat-form-field >
<mat-label>{{appConstant.forms.signup.password.label}}</mat-label>
<input type="password" matInput [formControlName]="appConstant.forms.signup.password.control">
<mat-error *ngIf="signupForm.controls[appConstant.forms.signup.password.control].hasError('required')">
This field is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>

<div class="col-12 sm:col-12 md:col-4 lg:col-4 xl:col-4">
<mat-form-field>
<mat-label>{{appConstant.forms.signup.dob.label}}</mat-label>
<input matInput [matDatepicker]="dob" appFormatDate [formControlName]="appConstant.forms.signup.dob.control">
<mat-hint>{{appConstant.forms.errors.datePicker.format.message}}</mat-hint>
<mat-datepicker-toggle matSuffix [for]="dob"></mat-datepicker-toggle>
<mat-datepicker #dob></mat-datepicker>
<mat-error>
{{appConstant.forms.errors.datePicker.notRequird.message}}
</mat-error>
</mat-form-field>
</div>

<div class="col-12 sm:col-12 md:col-4 lg:col-4 xl:col-4">
<mat-form-field >
<mat-label>{{appConstant.forms.signup.address.label}}</mat-label>
<input type="text" matInput [formControlName]="appConstant.forms.signup.address.control">
<mat-error *ngIf="signupForm.controls[appConstant.forms.signup.address.control].hasError('required')">
This field is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>

<div class="col-12 sm:col-12 md:col-4 lg:col-4 xl:col-4">
<mat-form-field >
<mat-label>{{appConstant.forms.signup.pincode.label}}</mat-label>
<input type="number" matInput [formControlName]="appConstant.forms.signup.pincode.control">
<mat-error *ngIf="signupForm.controls[appConstant.forms.signup.pincode.control].hasError('required')">
This field is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>

<div class="grid">
<div class="col-12 sm:col-12 md:col-12 lg:col-12 xl:col-12 text-right">
<div class="signup-buttons">
<button type="submit" [disabled]="!signupForm.valid" mat-raised-button color="primary">Register</button>
</div>
</div>
</div>

</form>

So we are using primeflex css libary in order to design the gird system with flexbox. you can install this library from primeNg by using this below npm command

npm install primeflex

We have added required validation and corresponding message to the html and also we have added the form validation for Angular Material Datepicker, So if someone will input any wrong value or string it will throw an error. We build this form using Angular Material and we use default features of Agular Material to validate the Reactive Form. So now when user will submit the form by validating all field then will some isValid block and from here you can do your signup api call in order to do the signup.

Conclusion:

We build this reactive form in order to showcase to you that how we can build a reusable reactive form that can be used in other components if it is required. We also shown you how you can use the constant to leverage the dynamic values instead making it hard coded in the html. So use this kind of pattern in order to create reactive form and you can multiple forms in services and inject in components.

--

--

Pritam Banerjee
Pritam Banerjee

Written by Pritam Banerjee

I am Full Stack Developer and Data Scientist, I have worked some of the biggest client’s project (eg. Walmart, Cisco, Uber, Apple, JP Morgan, Capital One etc).

No responses yet