August 7, 2026
Angular reactive forms tutorial with FormBuilder and FormGroup

Angular Reactive Forms Tutorial (2026 Edition) — Part 2

Updated for Angular 19 — June 29, 2026 · Reactive forms with FormBuilder, validators, and valueChanges. All Angular tutorials

Complete guide: Angular Reactive Forms Validation — Complete Guide (2026)

Kindson Munonye · Software engineer & technical author
GitHub · LinkedIn · About · YouTube
Last updated by Kindson Munonye — June 29, 2026


📚 Tutorial hub: Angular tutorials · CRUD series

Continue the series: Part 1: Template-driven forms · Form validation guide

Prerequisites: Complete Part 1: Template-driven forms first.

Estimated time: ~45 minutes · Last updated: June 29, 2026

📚 Browse all tutorials: Angular tutorials hub · Part 1: Template-driven forms

In this simple tutorial, we would cover Reactive Forms in Angular. This follows from Part 1. There we covered Template-Driven Forms.

According to Angular documentation, reactive forms make use of explicit and immutable approach to managing the forms state. It is also based on observable streams. Moreover, reactive forms are more predictable with synchronous access to data model.

Step 1: So you need to create a new component and setup the basic form like before. I call this component rform.

Next, add the markup [formGroup] attribute to the form. Set it’s value as well. I named it rform but you can use any other name:

[formGroup] = "rform"

Once, you do this, you have to import the Reactive form module.

Then you’ll create a field rform of type FormGroup (requires you import FormGroup as well)

 

Build the Form

We now need to build the form using FormBuilder. This makes it a lot easier.

First add the FormControlName attribute to all the form controls in the html. So the markup for the form controls in the HTML would be like this:

<form>
  <div class="form-group">
    <label>id</label>
    <input class="form-control" formControlName="id">
  </div>
  <div class="form-group">
    <label>Name</label>
    <input class="form-control" formControlName="name">
  </div>
  <div class="form-group">
    <label >Department</label>
    <input class="form-control" formControlName="department">
  </div>
  <select class="form-control" formControlName="country"> 
    <option> </option> 
  </select>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>

Next, add a FormBuilder variable as a parameter to the constructor (remember also to import FormBuilder).

Finally you build the form in the ngOnInit() method. Or just in the class. This is easy too. See the code below. So you can build any kind of form based on the html form markup.

    this.rform = this.fb.group({
      id: [''],
      name: [''],
      department: [''],
      country: ['']
    });

So what happens here is that the form is built and each control value is initialised as an empty string.

 

Form Submission

To handle form submission, we would add a submit event to the form like this:

 (ngSubmit)="send()"

Then we write the event handler. We can use console.log() to check what happens when values changes.

 

Dropdownlist Items

We use the same method we used in Template-driven forms. Create the list of item in the ts file. Then in the html markup for the select, we have:

<select class="form-control" formControlName="country">
  <option *ngFor="let country of countries" value={{country}}>
    {{country}}
  </option>
</select>

Built-in Validators in Reactive Forms

Import validators from @angular/forms and pass them as the second argument in each control array:

import {{ Validators }} from '@angular/forms';

this.employeeForm = this.fb.group({{
  firstname: ['', [Validators.required, Validators.minLength(2)]],
  email: ['', [Validators.required, Validators.email]],
  age: [null, [Validators.required, Validators.min(18), Validators.max(65)]]
}});

Display errors in the template using formControlName references:

<input formControlName="email" class="form-control">
<span *ngIf="employeeForm.get('email')?.invalid && employeeForm.get('email')?.touched">
  Enter a valid email
</span>

Custom Validators

Create a reusable validator function. This example rejects whitespace-only names:

export function noWhitespace(control: AbstractControl): ValidationErrors | null {{
  const value = (control.value || '').trim();
  return value.length === 0 ? {{ whitespace: true }} : null;
}}

// Usage
firstname: ['', [Validators.required, noWhitespace]]

See the full validation walkthrough in Form Validation in Angular.

Tracking Changes with valueChanges

Reactive forms expose an observable stream when any control value changes — ideal for dependent dropdowns (e.g. load states when country changes):

this.employeeForm.get('country')?.valueChanges.subscribe(country => {{
  this.states = this.stateService.getStatesFor(country);
  this.employeeForm.patchValue({{ state: '' }});
}});

Reactive Forms in Standalone Components (Angular 19)

import {{ ReactiveFormsModule, FormBuilder }} from '@angular/forms';

@Component({{
  standalone: true,
  imports: [ReactiveFormsModule],
  templateUrl: './employee-form.component.html'
}})
export class EmployeeFormComponent {{
  constructor(private fb: FormBuilder) {{
    this.employeeForm = this.fb.group({{ /* controls */ }});
  }}
}}

Form Submission Best Practices

  • Disable the submit button when employeeForm.invalid
  • Call markAllAsTouched() on failed submit to reveal errors
  • Use getRawValue() if disabled controls should be included

Next step: Form Validation in Angular — Step by Step

Working with FormArray (Dynamic Fields)

When users can add multiple phone numbers, skills, or line items, use FormArray:

import {{ FormArray, FormControl }} from '@angular/forms';

skills = this.fb.array([this.fb.control('')]);

addSkill() {{ this.skills.push(this.fb.control('')); }}
removeSkill(i: number) {{ this.skills.removeAt(i); }}

get skillControls() {{ return (this.employeeForm.get('skills') as FormArray).controls; }}
<div formArrayName="skills">
  <div *ngFor="let ctrl of skillControls; let i = index">
    <input [formControlName]="i" class="form-control">
    <button type="button" (click)="removeSkill(i)">Remove</button>
  </div>
</div>
<button type="button" (click)="addSkill()">Add skill</button>

Nested FormGroups

Model addresses or payment details with nested groups:

this.employeeForm = this.fb.group({{
  name: ['', Validators.required],
  address: this.fb.group({{
    street: ['', Validators.required],
    city: ['', Validators.required],
    zip: ['', Validators.pattern(/^\d{{5}}$/)],
  }})
}});
<div formGroupName="address">
  <input formControlName="street" placeholder="Street">
  <input formControlName="city" placeholder="City">
</div>

Async Validators (Check Username Availability)

Use async validators for server-side checks. They return an Observable:

import {{ of }} from 'rxjs';
import {{ delay, map }} from 'rxjs/operators';

function usernameTakenValidator(userService: UserService): AsyncValidatorFn {{
  return (control: AbstractControl) =>
    userService.isTaken(control.value).pipe(
      map(taken => (taken ? {{ usernameTaken: true }} : null))
    );
}}

username: ['', [Validators.required], [usernameTakenValidator(this.userService)]]

Show a loading indicator while async validation runs using pending status on the control.

patchValue vs setValue

  • setValue() — requires every control; throws if any are missing
  • patchValue() — updates only provided fields; ideal for edit forms loading API data
  • reset() — clears the form back to initial state
// Load employee for editing
this.employeeService.get(id).subscribe(emp => {{
  this.employeeForm.patchValue(emp);
}});

When to Choose Reactive vs Template-Driven

Use reactive forms whenUse template-driven when
Complex validation logicSimple login/search forms
Dynamic fields (FormArray)Prototyping quickly
Unit testing form logicMinimal TypeScript setup
Programmatic value changesFamiliar AngularJS-style binding

Most production Angular apps prefer reactive forms for maintainability. Review Part 1 for template-driven basics, then apply validation in the validation guide.




Kindson Munonye

Kindson Munonye is a software engineer and technical author specializing in Angular, Spring Boot, and microservices architecture. He publishes step-by-step tutorials with source code covering CRUD operations, reactive forms, CQRS, event sourcing, and REST API integration.GitHub · LinkedIn · About · YouTube

View all posts by Kindson Munonye →
0 0 votes
Article Rating
Subscribe
Notify of
guest
4 Comments
Oldest
Newest Most Voted
trackback

[…] Continue the series: Part 2: Reactive Forms […]

trackback

[…] Related: Template-driven forms · Reactive forms […]

trackback

[…] is the definitive guide to validation in Angular reactive forms. It combines and extends our Reactive Forms tutorial and Form Validation guide with Angular 19 patterns, custom validators, async checks, and […]

trackback

[…] reactive forms guide for validated prompt […]