Blazor : formulaires & validation
Construire un formulaire avec EditForm, lier les champs via les composants Input*, valider avec les DataAnnotations, afficher les erreurs (ValidationMessage) et réagir à la soumission.
Blazor : formulaires & validation
Un formulaire, c'est partout : une connexion, une inscription, un bon de commande. À chaque fois, les mêmes besoins : relier les champs à des données, vérifier qu'elles sont valides (champ obligatoire, e-mail correct, âge minimum), afficher les erreurs, puis réagir quand l'utilisateur envoie. Blazor fournit une boîte à outils dédiée qui orchestre tout ça : EditForm.
Si tu n'as pas lu le data binding, commence par là : les formulaires reposent dessus.
# Le problème que ça résout
Sans outillage, tu devrais, pour chaque champ : le lier à une variable, écrire la règle de validation à la main, décider quand la vérifier, et afficher le message d'erreur au bon endroit. Répétitif et fragile.
EditForm regroupe trois choses en un système cohérent :
- un modèle (un objet C# qui porte les données du formulaire),
- la validation (des règles déclarées sur ce modèle),
- la soumission (un handler appelé seulement si tout est valide).
# Un exemple complet
On part d'une inscription. D'abord le modèle, une simple classe C# dont les propriétés portent des règles sous forme d'attributs (les DataAnnotations) :
using System.ComponentModel.DataAnnotations;
public class Inscription
{
[Required(ErrorMessage = "Le nom est obligatoire")]
public string Nom { get; set; } = "";
[Required, EmailAddress(ErrorMessage = "Email invalide")]
public string Email { get; set; } = "";
[Range(18, 120, ErrorMessage = "Tu dois avoir au moins 18 ans")]
public int Age { get; set; }
}using System.ComponentModel.DataAnnotations; public class Inscription{ [Required(ErrorMessage = "Le nom est obligatoire")] public string Nom { get; set; } = ""; [Required, EmailAddress(ErrorMessage = "Email invalide")] public string Email { get; set; } = ""; [Range(18, 120, ErrorMessage = "Tu dois avoir au moins 18 ans")] public int Age { get; set; }}Ensuite le formulaire, qui référence ce modèle :
<EditForm Model="inscription" OnValidSubmit="Enregistrer">
<DataAnnotationsValidator />
<label>Nom</label>
<InputText @bind-Value="inscription.Nom" />
<ValidationMessage For="() => inscription.Nom" />
<label>Email</label>
<InputText @bind-Value="inscription.Email" />
<ValidationMessage For="() => inscription.Email" />
<label>Âge</label>
<InputNumber @bind-Value="inscription.Age" />
<ValidationMessage For="() => inscription.Age" />
<button type="submit">S'inscrire</button>
</EditForm>
@code {
private Inscription inscription = new();
private void Enregistrer()
{
// Appelé UNIQUEMENT si le formulaire est valide
}
}<EditForm Model="inscription" OnValidSubmit="Enregistrer"> <DataAnnotationsValidator /> <label>Nom</label> <InputText @bind-Value="inscription.Nom" /> <ValidationMessage For="() => inscription.Nom" /> <label>Email</label> <InputText @bind-Value="inscription.Email" /> <ValidationMessage For="() => inscription.Email" /> <label>Âge</label> <InputNumber @bind-Value="inscription.Age" /> <ValidationMessage For="() => inscription.Age" /> <button type="submit">S'inscrire</button></EditForm> @code { private Inscription inscription = new(); private void Enregistrer() { // Appelé UNIQUEMENT si le formulaire est valide }}C'est tout. On décortique maintenant chaque brique.
# Les composants Input*
À l'intérieur d'un EditForm, on n'utilise pas de <input> HTML brut mais les composants Input* de Blazor. Leur avantage : ils sont connectés à la validation (ils savent afficher l'état valide/invalide, et signaler le champ modifié).
| Composant | Pour |
|---|---|
InputText | texte, e-mail |
InputTextArea | texte long |
InputNumber | nombres |
InputCheckbox | booléen (case à cocher) |
InputSelect | liste déroulante |
InputDate | dates |
InputRadioGroup | boutons radio |
On les lie au modèle avec @bind-Value (la mécanique Value / ValueChanged vue dans le data binding) :
<InputText @bind-Value="inscription.Nom" /><InputText @bind-Value="inscription.Nom" /># La validation : les DataAnnotations
Les règles ne vivent pas dans le formulaire mais sur le modèle, sous forme d'attributs. Les plus courants :
| Attribut | Vérifie |
|---|---|
[Required] | le champ n'est pas vide |
[EmailAddress] | format d'e-mail |
[StringLength(50)], [MinLength], [MaxLength] | longueur du texte |
[Range(18, 120)] | bornes d'un nombre |
[Compare(nameof(MotDePasse))] | égalité (ex. confirmer un mot de passe) |
[RegularExpression("...")] | correspond à un motif |
Pour que le formulaire applique ces règles, on pose un <DataAnnotationsValidator /> à l'intérieur de l'EditForm. Sans lui, les attributs sont ignorés. La validation se déclenche alors à la soumission et quand l'utilisateur modifie un champ.
Mettre les règles sur le modèle, c'est puissant : le même modèle validé côté client peut l'être aussi côté serveur (l'API réutilise les mêmes attributs). Une seule source de vérité pour « qu'est-ce qu'une inscription valide ».
# Afficher les erreurs
Deux composants pour montrer les messages à l'utilisateur :
<ValidationMessage For="() => inscription.Email" />: l'erreur d'un champ précis, à placer juste sous lui. LeForpointe vers la propriété concernée.<ValidationSummary />: la liste de toutes les erreurs, en général en haut du formulaire.
<ValidationSummary />
...
<InputText @bind-Value="inscription.Email" />
<ValidationMessage For="() => inscription.Email" /><ValidationSummary />...<InputText @bind-Value="inscription.Email" /><ValidationMessage For="() => inscription.Email" />Les composants Input* ajoutent aussi des classes CSS (valid, invalid, modified) que tu peux styliser pour un retour visuel (bordure rouge/verte).
# Réagir à la soumission
EditForm expose trois événements, selon ton besoin :
| Événement | Déclenché |
|---|---|
OnValidSubmit | à l'envoi, seulement si tout est valide |
OnInvalidSubmit | à l'envoi, s'il y a des erreurs |
OnSubmit | à chaque envoi (tu valides toi-même) |
Le cas courant : OnValidSubmit. Le handler n'est appelé que si le modèle passe toutes les règles, donc pas besoin de re-vérifier dedans.
<EditForm Model="inscription" OnValidSubmit="Enregistrer">
...
</EditForm>
@code {
private async Task Enregistrer()
{
await Service.CreerCompteAsync(inscription); // les données sont déjà valides
}
}<EditForm Model="inscription" OnValidSubmit="Enregistrer"> ...</EditForm> @code { private async Task Enregistrer() { await Service.CreerCompteAsync(inscription); // les données sont déjà valides }}# Au-delà des DataAnnotations
Pour des règles qui dépassent les attributs (validation croisée entre plusieurs champs, appel à une base pour vérifier qu'un e-mail est libre), on passe par l'EditContext : l'objet que EditForm gère en coulisses, sur lequel on peut déclencher et écouter la validation manuellement. Pour des règles riches, beaucoup d'équipes utilisent aussi FluentValidation (via un package communautaire) au lieu des attributs.
# À retenir
- Un formulaire = un
EditFormautour d'un modèle (objet C#), avec des composantsInput*liés par@bind-Value. - Les règles vivent sur le modèle via les DataAnnotations (
[Required],[EmailAddress],[Range]...). - Il faut un
<DataAnnotationsValidator />dans l'EditFormpour que ces règles s'appliquent. - On affiche les erreurs avec
ValidationMessage(un champ) etValidationSummary(toutes). OnValidSubmitn'appelle ton handler que si le formulaire est valide.- Bonus : le même modèle validé peut l'être côté serveur, et
EditContext/ FluentValidation gèrent les cas complexes.