Angular is a powerful and popular front-end framework that allows developers to build dynamic and interactive web applications. One of Angular's key features is its ability to seamlessly process modules. In this blog post, we will explore the concept of dynamic forms in Angular and explore how JSON can be utilized to create dynamic and flexible forms.
What are Dynamic Forms?
Dynamic forms in Angular are forms that are generated dynamically at runtime based on certain conditions or data. Unlike static forms, where the structure is predefined in the HTML, dynamic forms are more flexible and can adapt to changing requirements. This is particularly useful in scenarios where the form structure needs to be determined dynamically based on user input, API responses, or other dynamic data sources.
Creating a Simple Dynamic Form
Let's walk through a basic example of creating a dynamic form using Angular and JSON.
Step 1: Set Up Your Angular Project
Assuming you have Angular CLI installed, create a new Angular project:
ng new dynamic-forms
cd dynamic-forms
Step 2: Install Required Dependencies
Install the Angular Reactive Forms module, which will be used to create and manage dynamic forms:
ng generate module dynamic-form
Step 3: Define interface
Create a file named form.interface.ts
to define the structure of your dynamic form interface:
export interface IFormStructure {
type: string;
label: string;
name: string;
value: string | number | boolean;
options?: { label: string; value: number | string | boolean }[];
validations?: {
name: string;
validator: string;
message: string;
}[];
}
Step 4: Define Form Structure in JSON
Create a file named form-config.ts
to define the structure of your dynamic form:
import { IFormStructure } from './form.interface';
export const formConfig: IFormStructure[] = [
{
type: 'text',
label: 'Name',
name: 'name',
value: '',
validations: [
{
name: 'required',
validator: 'required',
message: 'Name is required',
},
],
},
{
type: 'textarea',
label: 'Description',
name: 'description',
value: '',
validations: [
{
name: 'required',
validator: 'required',
message: 'Description is required',
},
],
},
{
type: 'number',
label: 'Age',
name: 'age',
value: '',
validations: [],
},
{
type: 'radio',
label: 'Gender',
name: 'gender',
value: true,
options: [
{ label: 'Male', value: true },
{ label: 'Female', value: false },
],
validations: [],
},
{
type: 'select',
label: 'Country',
name: 'country',
value: 1,
options: [
{ label: 'India', value: 1 },
{ label: 'USA', value: 2 },
{ label: 'Canada', value: 3 },
],
validations: [
{
name: 'required',
validator: 'required',
message: 'Address is required',
},
],
},
];
Step 5: Create Dynamic Form Component
Generate a new component to handle the dynamic form:
ng generate component dynamic-form
Step 6: Dynamically Generate Form
Update the dynamic-form.component.ts
file to dynamically generate the form based on the JSON configuration:
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { IFormStructure } from './form.interface';
import { formConfig } from './form-config';
@Component({
selector: 'app-dynamic-form',
templateUrl: './dynamic-form.component.html',
styleUrls: ['./dynamic-form.component.scss'],
})
export class DynamicFormComponent implements OnInit {
formStructure: IFormStructure[] = formConfig;
dynamicForm: FormGroup = this.fb.group({});
constructor(private fb: FormBuilder) {
let formGroup: Record<string, any> = {};
this.formStructure.forEach((control) => {
let controlValidators: Validators[] = [];
if (control.validations) {
``;
control.validations.forEach(
(validation: {
name: string;
validator: string;
message: string;
}) => {
if (validation.validator === 'required')
controlValidators.push(Validators.required);
if (validation.validator === 'email')
controlValidators.push(Validators.email);
// Add more built-in validators as needed
}
);
}
formGroup[control.name] = [control.value || '', controlValidators];
});
this.dynamicForm = this.fb.group(formGroup);
}
getErrorMessage(control: any) {
const formControl = this.dynamicForm.get(control.name);
if (!formControl) {
return '';
}
for (let validation of control.validations) {
if (formControl.hasError(validation.name)) {
return validation.message;
}
}
return '';
}
onSubmit() {
if (!this.dynamicForm.valid) {
this.dynamicForm.markAllAsTouched();
return;
}
console.log(this.dynamicForm.value);
}
}
```
Step 7: Import `bootstrap.css` in `style.css/scss` file
```css
@import "https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css";
```
**Step 8: Display the Form in the Template**
Update the `dynamic-form.component.html` file to display the dynamic form:
```html
<div class="card">
<div class="card-body">
<form [formGroup]="dynamicForm" (ngSubmit)="onSubmit()">
<div class="row">
<div *ngFor="let control of formStructure" class="col-3">
<!-- Text, Textarea & Number -->
<div
class="mb-3"
*ngIf="['text', 'number', 'textarea'].includes(control.type)"
>
<label for="exampleFormControlInput1" class="form-label">
{{ control.label }}
</label>
<input
[type]="control.type"
class="form-control"
[formControlName]="control.name"
*ngIf="control.type !== 'textarea'"
/>
<textarea
class="form-control"
[formControlName]="control.name"
*ngIf="control.type === 'textarea'"
>
</textarea>
<span
class="error"
*ngIf="
dynamicForm.controls[control.name]?.invalid &&
dynamicForm.controls[control.name]?.touched
"
>
{{ getErrorMessage(control) }}
</span>
</div>
<!-- Radio Button -->
<div class="mb-3" *ngIf="['radio'].includes(control.type)">
<div>
<label for="exampleFormControlInput1" class="form-label">
{{ control.label }}
</label>
</div>
<div
class="form-check form-check-inline"
*ngFor="let option of control.options"
>
<input
class="form-check-input"
type="radio"
[formControlName]="control.name"
id="inlineRadio1"
[value]="option.value"
/>
<label class="form-check-label" for="inlineRadio1">
{{ option.label }}</label
>
</div>
</div>
<!-- Select -->
<div class="mb-3" *ngIf="['select'].includes(control.type)">
<label for="exampleFormControlInput1" class="form-label">
{{ control.label }}
</label>
<select
class="form-select"
aria-label="Default select example"
[formControlName]="control.name"
>
<option selected>-Select-</option>
<option
*ngFor="let option of control.options"
[value]="option.value"
>
{{ option.label }}
</option>
</select>
<span
class="error"
*ngIf="
dynamicForm.controls[control.name]?.invalid &&
dynamicForm.controls[control.name]?.touched
"
>
{{ getErrorMessage(control) }}
</span>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
```
**Step 9: Integrate the Dynamic Form Component**
Integrate the DynamicFormComponent into your main application by adding it to the `app.component.html` file or any other desired location.
```html
<app-dynamic-form></app-dynamic-form>
```
**Step 10: Run Your Angular Application**
Run your Angular application to see the dynamically generated form in action:
```bash
ng serve
```
Visit `http://localhost:4200/` in your browser to interact with the dynamic form.
**Output**
![dynamicform](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1omp4qvsvw5023f4omg7.png)
## Conclusion
In this blog post, we explored the concept of dynamic forms in Angular and how JSON can be leveraged to define the structure of these forms. By using Angular Reactive Forms and dynamically generating form controls based on JSON configuration, developers can create flexible and adaptive forms that cater to diverse requirements. This approach enhances maintainability and makes it easier to handle dynamic form scenarios in Angular applications.
Top comments (2)
Excellent!! thanks!
Thanks so much! It works great!