typescript 60 lines · 10 steps

A reactive signup form in Angular

A standalone Angular component builds a validated form, posts it, and folds server-side validation errors back onto the right fields.

Explained by highlit
1import { Component, inject } from '@angular/core';
2import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
3import { HttpClient, HttpErrorResponse } from '@angular/common/http';
4import { finalize } from 'rxjs';
5 
6interface ValidationError {
7 message: string;
8 errors: Record<string, string[]>;
9}
10 
11@Component({
12 selector: 'app-signup-form',
13 standalone: true,
14 imports: [ReactiveFormsModule],
15 templateUrl: './signup-form.component.html',
16})
17export class SignupFormComponent {
18 private readonly fb = inject(FormBuilder);
19 private readonly http = inject(HttpClient);
20 
21 submitting = false;
22 
23 readonly form = this.fb.group({
24 name: ['', Validators.required],
25 email: ['', [Validators.required, Validators.email]],
26 password: ['', [Validators.required, Validators.minLength(8)]],
27 });
28 
29 submit(): void {
30 if (this.form.invalid) {
31 this.form.markAllAsTouched();
32 return;
33 }
34 
35 this.submitting = true;
36 this.http
37 .post('/api/users', this.form.getRawValue())
38 .pipe(finalize(() => (this.submitting = false)))
39 .subscribe({
40 next: () => this.form.reset(),
41 error: (err: HttpErrorResponse) => this.applyServerErrors(err),
42 });
43 }
44 
45 private applyServerErrors(err: HttpErrorResponse): void {
46 if (err.status !== 422) {
47 return;
48 }
49 
50 const body = err.error as ValidationError;
51 for (const [field, messages] of Object.entries(body.errors ?? {})) {
52 const control = this.form.get(field);
53 if (!control) {
54 continue;
55 }
56 control.setErrors({ ...control.errors, server: messages[0] });
57 control.markAsTouched();
58 }
59 }
60}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Reactive forms let you declare validation rules up front and check validity before any network call.
  2. 2A finalize operator guarantees cleanup like resetting a loading flag whether the request succeeds or fails.
  3. 3Mapping a 422 response back onto individual controls turns server validation into inline field errors.

Related explainers

Share this explainer

Here's the card — post it anywhere.

A reactive signup form in Angular — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code