Prompt

angular dynamic form builder

Technology · Developer Tools / Developer tools3 observationsLast seen Jul 21, 2026

Latest observation

Jul 21, 2026 · Gemini

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.

  1. 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; }

  2. 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>
  1. 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.