Prompt
angular dynamic form builder
Latest observation
Building a dynamic form in Angular allows you to generate form controls at runtime based on a JSON configuration object. This approach is ideal for metadata-driven UIs, survey builders, or enterprise applications with constantly changing inputs. Here is a step-by-step breakdown of how to construct a clean, scalable Angular dynamic form builder using Reactive Forms.
-
Define the Form Model Interface Start by defining the structure of the JSON schema that will describe each input field. TypeScript // dynamic-field.interface.ts export interface DynamicField { key: string; label: string; type: 'text' | 'number' | 'select' | 'checkbox'; value?: any; options?: { key: string; value: string }[]; // For select inputs required?: boolean; }
-
Dynamic Form Component Implementation Create a component that consumes the metadata schema, generates an FormGroup, and renders controls dynamically using @switch (or ngSwitch). Component Logic (dynamic-form.component.ts) TypeScript import { Component, Input, OnInit, inject } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms'; import { DynamicField } from './dynamic-field.interface';
@Component({ selector: 'app-dynamic-form', standalone: true, imports: [CommonModule, ReactiveFormsModule], templateUrl: './dynamic-form.component.html' }) export class DynamicFormComponent implements OnInit { @Input({ required: true }) fields: DynamicField[] = [];
private fb = inject(FormBuilder); form!: FormGroup;
ngOnInit(): void { this.form = this.createFormGroup(); }
private createFormGroup(): FormGroup { const group = this.fb.group({});
this.fields.forEach((field) => {
const validators = field.required ? [Validators.required] : [];
group.addControl(
field.key,
this.fb.control(field.value ?? '', validators)
);
});
return group;
}
onSubmit(): void { if (this.form.valid) { console.log('Form Submitted Payload:', this.form.value); } else { this.form.markAllAsTouched(); } } }
Component Template (dynamic-form.component.html) HTML
<form [formGroup]="form" (ngSubmit)="onSubmit()"> @for (field of fields; track field.key) { <div class="form-group mb-3"> <label [for]="field.key" class="form-label">{{ field.label }}</label> @switch (field.type) {
@case ('text') {
<input
[id]="field.key"
type="text"
[formControlName]="field.key"
class="form-control"
/>
}
@case ('number') {
<input
[id]="field.key"
type="number"
[formControlName]="field.key"
class="form-control"
/>
}
@case ('select') {
<select [id]="field.key" [formControlName]="field.key" class="form-select">
<option value="">Select an option</option>
@for (opt of field.options; track opt.key) {
<option [value]="opt.key">{{ opt.value }}</option>
}
</select>
}
@case ('checkbox') {
<div class="form-check">
<input
[id]="field.key"
type="checkbox"
[formControlName]="field.key"
class="form-check-input"
/>
</div>
}
}
@if (form.get(field.key)?.invalid && form.get(field.key)?.touched) {
<small class="text-danger">{{ field.label }} is required.</small>
}
</div>
}
<button type="submit" [disabled]="form.invalid" class="btn btn-primary"> Submit </button>
</form>- Passing Data from Parent Component To use the dynamic form, supply the field metadata config array from your parent component: TypeScript // app.component.ts import { Component } from '@angular/core'; import { DynamicFormComponent } from './dynamic-form/dynamic-form.component'; import { DynamicField } from './dynamic-form/dynamic-field.interface';
@Component({
selector: 'app-root',
standalone: true,
imports: [DynamicFormComponent],
template: <div class="container mt-4"> <h2>Dynamic Form Sample</h2> <app-dynamic-form [fields]="userFormSchema" /> </div>
})
export class AppComponent {
userFormSchema: DynamicField[] = [
{
key: 'fullName',
label: 'Full Name',
type: 'text',
required: true
},
{
key: 'age',
label: 'Age',
type: 'number',
value: 25
},
{
key: 'role',
label: 'User Role',
type: 'select',
required: true,
options: [
{ key: 'admin', value: 'Administrator' },
{ key: 'user', value: 'Standard User' }
]
},
{
key: 'acceptTerms',
label: 'I accept the terms and conditions',
type: 'checkbox',
required: true
}
];
}
Architectural Comparison & Options When implementing dynamic forms in production, consider these architectural approaches: Custom Reactive Form Builder (Shown Above) Pros: Zero external dependencies, highly customizable, light footprint. Cons: Requires manual maintenance for complex fields (e.g., dynamic arrays, multi-step forms). Formly (@ngx-formly/core) Pros: Industry-standard library for JSON-powered Angular forms, supports complex conditional logic and custom templates out-of-the-box. Cons: Adds external dependency overhead to the project. Angular Dynamic Form Control via NgComponentOutlet Pros: Complete separation of concerns by dynamically rendering custom component classes per input type. Cons: Higher boilerplate setup for basic forms. Where would you like to take this next?
Observation history
See 2 earlier observations
Create a free Obsurfable account to unlock historical responses, model comparisons, and deeper brand intelligence.
How did Obsurfable measure this prompt?
Obsurfable records AI answers to buyer-style prompts in its research corpus (3 observations for this page). Metrics are distributions over observations, not a single static ranking.
Which AI systems does Obsurfable collect answers from?
OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, and Meta AI.