Angular: Creating Dynamic Forms with Reactive Forms
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!