Skip to the solution
MediumFrontend10 min read

What is the difference between reactive and template-driven forms?

619 views

The problem

Question presented to candidate: "We have a two-field newsletter box built with ngModel, and a twelve-step onboarding wizard. What is the difference between template-driven and reactive forms, and which would you use for each?"

What a strong answer should cover:

  • Both are built on the same classes (FormControl, FormGroup); the difference is who creates the form model: the template (ngModel + name) or the component class (new FormGroup(...)).
  • Template-driven (FormsModule): two-way binding to plain fields, validation through attributes, controls registered asynchronously (a microtask after the view is created).
  • Reactive (ReactiveFormsModule): the model exists synchronously in the constructor, is strongly typed since v14, exposes valueChanges/statusChanges/events Observables, and is easy to unit test without a DOM.
  • Dynamic structure (adding fields, swapping validators, cross-field rules) is natural in reactive forms and awkward in templates.
  • Pick by complexity: template-driven for small, static forms; reactive for anything dynamic, large or heavily validated. Mention Signal Forms (stable in v22) as the new third option.

Clarifying questions expected:

  • "Is the structure of the form known up front, or does it change at runtime?"
  • "Do we need to unit test validation logic without rendering the component?"

Code / implementation expected: Optional β€” the same field written both ways, ideally showing the template-driven control appearing a tick later.

  • forms

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

10 min read Β· 10 sections

Read the code

AngularThe same email field built both ways, with the template-driven microtask delay logged
import { AfterViewInit, Component, ViewChild, signal } from "@angular/core";
import { JsonPipe } from "@angular/common";
import { FormControl, FormGroup, FormsModule, NgForm, ReactiveFormsModule, Validators } from "@angular/forms";

// Template-driven: the template creates the controls (ngModel + name).
@Component({
  selector: "td-signup",
  imports: [FormsModule, JsonPipe],
  template: `
    <form #f="ngForm">
      <input id="td-email" name="email" [(ngModel)]="email" required />
      <span class="td-out">TD value={{ f.value | json }} valid={{ f.valid }}</span>
    </form>
  `,
})
export class TdSignup implements AfterViewInit {
  @ViewChild("f") form!: NgForm;
  email = "ada@example.com";
  ngAfterViewInit() {
    // Controls are registered in a microtask, so they are not there yet.
    console.log("TD  ngAfterViewInit:", JSON.stringify(this.form.value));
    Promise.resolve().then(() => console.log("TD  after microtask:", JSON.stringify(this.form.value)));
  }
}

// Reactive: the class creates the controls; the template only binds to them.
@Component({
  selector: "rx-signup",
  imports: [ReactiveFormsModule],
  template: `
    <form [formGroup]="form">
      <input id="rx-email" formControlName="email" />
      <span class="rx-out">RX value={{ value() }} valid={{ form.valid }}</span>
    </form>
  `,
})
export class RxSignup {
  form = new FormGroup({
    email: new FormControl("ada@example.com", { nonNullable: true, validators: [Validators.required, Validators.email] }),
  });
  value = signal(JSON.stringify(this.form.value));
  constructor() {
    // The model exists before the view does, and it is a stream you can subscribe to.
    console.log("RX  constructor:", JSON.stringify(this.form.value));
    this.form.valueChanges.subscribe((v) => this.value.set(JSON.stringify(v)));
  }
}

@Component({
  selector: "app-root",
  imports: [TdSignup, RxSignup],
  template: `<td-signup /><hr /><rx-signup />`,
})
export class AppComponent {}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 43 of 121 in Angular

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Angular questions
Up nextMedium

afterRender vs afterNextRender vs ngAfterViewInit β€” which to use?

Continue