Angular: Creating Dynamic Forms with Reactive Forms

Abhishek Wadalkar
3 min readNov 1, 2024

--

Building forms in Angular can often be tedious, especially when it comes to handling validation, model definition, and user interactions. Fortunately, Angular’s Reactive Forms module allows us to create dynamic forms that adapt to varying configurations without rewriting code. In this post, we will create a dynamic form component that generates form controls based on a JSON configuration.

Step 1: Setting Up the Dynamic Control Interface

First, we define an interface to represent our dynamic form controls. This interface will dictate the structure of each form field.

export interface DynamicControl {
controlKey: string;
formFieldType?: ‘input’ | ‘select’;
inputType?: string;
label?: string;
defaultValue?: any;
selectOptions?: string[];
updateOn: ‘change’ | ‘blur’ | ‘submit’;
validators?: ValidatorFn[];
}

Step 2: Creating the Dynamic Form Component

Next, we create a new component called DynamicFormComponent. This component will take an array of DynamicControl objects and dynamically generate form controls based on this configuration.

DynamicFormComponent Class

In dynamic-form.component.ts, we implement the necessary logic to build the form model:

import { Component, Input, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { DynamicControl } from './dynamic-control.interfaces';

@Component({
selector: 'app-dynamic-form',
templateUrl: './dynamic-form.component.html'
})
export class DynamicFormComponent implements OnChanges {
@Input() formModelConfig: DynamicControl[] = [];
@Output() outputForm = new EventEmitter();

formModel = new FormGroup({});

ngOnChanges(changes: SimpleChanges) {
if (changes['formModelConfig']) {
this.formModel = new FormGroup({});
this.formModelConfig.forEach(control => {
this.formModel.addControl(
control.controlKey,
new FormControl(control.defaultValue, {
updateOn: control.updateOn,
validators: control.validators
})
);
});
}
}

onSubmit() {
this.outputForm.emit(structuredClone(this.formModel.value));
this.formModel.reset();
}
}

Step 3: Creating the Template

Now we need to construct the HTML template that will display our dynamic form. In dynamic-form.component.html, we will iterate over formModelConfig and use Angular directives to create the appropriate form controls:

<div class="form-container">
<form [formGroup]="formModel" (ngSubmit)="onSubmit()">
<div class="form-field" *ngFor="let control of formModelConfig">
<label for="{{control.controlKey}}">{{ control.label }}</label>
<ng-container [ngSwitch]="control.formFieldType">
<input *ngSwitchCase="'input'"
formControlName="{{ control.controlKey }}"
type="{{ control.inputType }}">
</ng-container>
<span *ngIf="formModel.get(control.controlKey)?.touched &&
formModel.get(control.controlKey)?.hasError('required')">
This field is required
</span>
</div>
<button type="submit">Submit</button>
</form>
</div>

Step 4: Testing the Dynamic Form

To test our dynamic form, we can import it into another component, such as ExpensesOverviewPageComponent, and define a configuration for our fields, specifically for “title” and “description”:

formModelConfig: DynamicControl[] = [
{
controlKey: 'title',
formFieldType: 'input',
inputType: 'text',
label: 'Title',
defaultValue: '',
updateOn: 'change',
validators: [Validators.required]
},
{
controlKey: 'description',
formFieldType: 'input',
inputType: 'text',
label: 'Description',
defaultValue: '',
updateOn: 'change',
validators: [Validators.required]
}
];

In the HTML template AppComponent, we include our dynamic form:

<app-dynamic-form [formModelConfig]="formModelConfig" 
(outputForm)="addExpense($event)"></app-dynamic-form>

Conclusion

This simple example demonstrates how to create a dynamic form in Angular using Reactive Forms. By leveraging a configuration-based approach, we can easily adapt the form structure to meet various requirements without duplicating code.

In this case, we used “title” and “description” as our dynamic fields, both of which require input. This approach can be extended to support more complex form structures, such as nested form groups or arrays. With a few adjustments, you can build powerful and flexible forms tailored to your application’s needs.

Stay tune for more Angular tutorials!

--

--

Abhishek Wadalkar
Abhishek Wadalkar

Written by Abhishek Wadalkar

Passionate Frontend developer with 4 years experience, crafting seamless, user-centric web experiences. Exploring the world of web development and constantly.

No responses yet