Formulaires Angular post-typed forms : zod/yup, validation serveur, hydration progressive

Formulaires Angular post-typed forms : zod/yup, validation serveur, hydration progressive

Aller plus loin que les typed forms Angular : schémas zod/yup, round-trip serveur, et hydration progressive avec @defer.

Aller plus loin que les typed forms Angular : schémas zod/yup, round-trip serveur, et hydration progressive avec @defer.

Les typed forms ont sécurisé les contrôles. En 2025, on ajoute un schéma unique (zod/yup), une validation serveur et une hydration progressive.

Schéma zod comme source de vérité

// src/app/forms/signup.schema.ts
import { z } from 'zod';

export const signupSchema = z.object({
  email: z.string().email(),
  password: z.string().min(12),
  newsletter: z.boolean().optional(),
});

export type Signup = z.infer<typeof signupSchema>;

FormGroup typé depuis le schéma

// src/app/forms/signup.form.ts
import { FormControl, FormGroup, NonNullableFormBuilder } from '@angular/forms';
import { signupSchema, Signup } from './signup.schema';

export function createSignupForm(fb: NonNullableFormBuilder) {
  return fb.group({
    email: fb.control<Signup['email']>(''),
    password: fb.control<Signup['password']>(''),
    newsletter: fb.control<Signup['newsletter']>(false),
  });
}

Validation client + serveur

// src/app/forms/signup.service.ts
import { HttpClient } from '@angular/common/http';
import { inject } from '@angular/core';
import { signupSchema, Signup } from './signup.schema';

export function useSignupService() {
  const http = inject(HttpClient);

  async function submit(data: Signup) {
    const parsed = signupSchema.safeParse(data);
    if (!parsed.success) throw parsed.error.flatten().fieldErrors;
    return http.post('/api/signup', parsed.data).toPromise();
  }

  return { submit };
}

Côté serveur, rejouez le même schéma (zod-node) ou un DTO NestJS validé, et renvoyez des erreurs structurées.

Hydration progressive du formulaire

<!-- page signup -->
<h1>Créer un compte</h1>
@defer (when visible()) {
  <app-signup-form></app-signup-form>
} @loading {
  <p>Chargement du formulaire...</p>
}

Le HTML SSR s'affiche vite; le JS du formulaire s'hydrate quand l'utilisateur scrolle.

Accessibilité et DX

  • Afficher les erreurs par champ dès la validation zod (aria-live="polite").
  • Utiliser FormControlStatus pour désactiver le bouton submit pendant l'appel serveur.
  • Tests : zod + @testing-library/angular pour vérifier l'erreur de schéma et la propagation UI.

Check-list

  • Un seul schéma (zod/yup) partagé client/serveur.
  • Typed forms pour la DX dans les composants.
  • Hydration progressive sur les formulaires lourds.
  • Validation serveur obligatoire avant création de compte.