Valider un formulaire avec Flutter
Valider un formulaire avec Flutter
-
Objectif
- Dans ce tutoriel, découvrez comment ajouter une validation à un formulaire
-
Présentation
- Un Form flutter est un composant essentiel du développement d’applications Fluter. Lorsque nous créons un formulaire, nous devons implémenter la validation, la soumission, etc. du formulaire. Dans ce tutoriel, vous apprendrez à créer, valider et utiliser un formulaire dans Flutter.
- La page de soumission de formulaire est utilisée pour soumettre les données saisies par l’utilisateur à partir du formulaire, et cela peut être fait de plusieurs façons en un clin d’œil.
- Les données du formulaire seront validées, et si la validation réussit, il soumettra les données. Si la validation échoue, un simple message d’erreur s’affichera pour nous informer de l’erreur.
- La création et la validation d’un formulaire comprennent les étapes suivantes :
- 1- Page de construction
- 2. Ajouter des validations
- 3. Ajouter une action pour valider le formulaire
-
Méthodes de validation de
TextFormFieldsavec Flutter - Flutter offre plusieurs méthodes de validation pour les TextFormField qui vous permettent de valider les données saisies par l’utilisateur.
- Les méthodes de validation les plus couramment utilisées incluent :
-
1. **Validation au moment de la soumission (on submission)** :
- Vous pouvez utiliser une ‘
formKey‘ assignée au widget ‘Form‘ pour déclencher la validation lorsque le formulaire est soumis. - Cela se révèle utile lorsque vous souhaitez effectuer une validation au moment où l’utilisateur appuie sur le bouton de soumission (‘
onPressed‘ du bouton de soumission). -
2. **Validation dès le rendu** :
- Pour déclencher une validation dès que le formulaire ou le champ est visible, utilisez `
AutovalidateMode.always`. -
3. **Validation lors d’un changement** :
- Pour déclencher une validation lorsqu’un champ est modifié, utilisez `
AutovalidateMode.onUserInteraction`. -
4. **Désactiver la validation** :
- Si vous voulez désactiver la validation, utilisez `
AutovalidateMode.disabled`. -
5. **Validation avec des expressions régulières (regex)** :
- L’expression
RegExp(r'[a-z]')est une expression régulière en Dart qui est utilisée pour rechercher une correspondance avec n’importe quelle lettre minuscule de l’alphabet anglais, c’est-à-dire une lettre comprise entre « a » et « z ». Voici ce que signifient les composants de cette expression régulière : RegExpest la classe en Dart utilisée pour représenter une expression régulière.rdevant la chaîne de caractères signifie que c’est une chaîne brute (raw string) où les caractères d’échappement ne sont pas interprétés. Cela permet de définir plus facilement des expressions régulières.[a-z]est une partie de l’expression régulière qui définit une plage de caractères autorisés. Dans ce cas, [a-z] signifie « n’importe quelle lettre minuscule de l’alphabet anglais », de « a » à « z ». La notation [a-z] est utilisée pour définir un ensemble de caractères autorisés. Si la chaîne de caractères contient au moins une lettre minuscule, alors la correspondance est vérifiée.- Utilisez une expression régulière pour valider une valeur. Par exemple, pour valider une adresse e-mail :
- L’expression régulière `
RegExp(r'^\S+@\S+$')` est couramment utilisée pour valider si une chaîne de caractères correspond à un format d’adresse e-mail simple. Voici ce que signifient les composants de cette expression régulière : - `
RegExp` est la classe en Dart utilisée pour représenter une expression régulière. - `
r` devant la chaîne de caractères signifie que c’est une chaîne brute (raw string) où les caractères d’échappement ne sont pas interprétés. - L’expression régulière elle-même est composée de trois parties principales :
- 1. `
^` : C’est un ancrage qui signifie « début de la chaîne ». L’expression commence par le début de la chaîne. - 2. `
\S+` : Cela correspond à un ou plusieurs caractères non-blancs. `\S` représente n’importe quel caractère qui n’est pas un espace blanc, et `+` signifie « un ou plusieurs ». Donc, `\S+` correspond à une séquence d’au moins un caractère non-blanc. - 3. `
@` : C’est simplement le caractère «at» (arobase) qui doit être présent dans une adresse e-mail valide. - 4. `
\S+` : Tout comme la première occurrence, cela correspond à une séquence d’au moins un caractère non-blanc. - 5. `
$` : C’est un ancrage qui signifie « fin de la chaîne ». L’expression se termine par la fin de la chaîne. -
6. **Valider des champs dépendants** :
-
7. **Erreurs de validation asynchrone** :
-
8. **Personnaliser l’apparence des champs de texte** :
-
Regle de validation d’un mot de passe
-
Étapes de validation du formulaire avec Flutter
-
Étape 1- Créer un formulaire avec un GlobalKey<FormState>.
- Utilisez d’abord le Widget
Form, cela fonctionnera en groupe et vous aidera à gérer facilement la validation de plusieurs champs de texte de formulaires flutter. - Ensuite, après avoir créé un formulaire en flutter, fournissez-lui
GlobalKey<FormState>, cela vous aidera à permettre à la validation de se former dans le bon ordre et très facilement. -
Étape 2- Ajoutez du TextFormField avec la validation requise.
- Le widget TextFormField provient de la conception matérielle et peut également afficher erreur de validation , chaque fois qu’un utilisateur ne remplit pas l’exigence TextFormField,
- nous pouvons le faire en appliquant des règles de validation à un champ de texte flutter particulier en lui fournissant des règles de propriétés de validation.
- Si l’utilisateur saisit une entrée non valide, la fonction
Validatordans Flutter la détectera et renverra un message d’erreur approprié au bas de TextField. -
Étape 3- Créez un bouton où vous vérifiez la validation du formulaire flutter et soumettez-le.
- La création d’un bouton devrait être à l’intérieur de Widget
Form, à l’aide duquel l’utilisateur peut soumettre le formulaire rempli d’informations. - Lorsqu’un utilisateur tente de soumettre le formulaire onPressed, nous vérifierons si le champ du formulaire flutetr par l’utilisateur est conforme à la validation requise, puis si le formulaire est valide, envoyez toutes les informations de données au serveur de base de données pour être enregistrées, sinon si le formulaire est invalid alors afficher un message d’erreur approprié à l’utilisateur sous le champ de texte flutter où la validation n’est pas autorisée.
-
Réalisation
- Nous allons donc créer un formulaire d’ inscription avec quelques champs :
- Prénom
- Nom de famille
- Mot de passe
- Confirmez le mot de passe
- et un bouton d’inscription .
-
Étape 1 : Créer un formulaire avec une
GlobalKey. - La clé globale (
GlobalKey) est utilisée pour identifier de manière unique le formulaire et permet la validation du formulaire lors d’une étape ultérieure. GlobalKey, il s’agit d’une clé unique sur l’ensemble de l’application. Grâce à cette clé, on peut trouver et accéder au Élément en question et récupérer sesStateet Widget.final _formKey = GlobalKey<FormState>();- Pour créer un formulaire, vous devez d’abord définir une clé globale (
GlobalKey). Dans notre exemple, nous avons défini a _formKey comme une clé globale. - Une clé globale ou
GlobalKeyest une clé qui, lorsqu’elle est transmise en tant que clé dans un widget, peut différencier le widget de tous les widgets d’une arborescence de widgets. - Tout d’abord, nous allons créer un formulaire. Le widget de formulaire agira comme un conteneur pour regrouper et valider plusieurs champs de formulaire.
- Pour identifier le formulaire de manière unique, nous devons fournir une
GlobalKeylors de la création du formulaire. -
Étape 2 : Ajouter un TextFormField avec une logique de validation
- L’étape suivante consiste à ajouter TextFormField. Ce widget affiche un champ de texte de conception de matériau et peut afficher les erreurs de validation lorsqu’elles se produisent.
- L’entrée est validée en fournissant une fonction validator() au TextFormField. Si la valeur saisie par l’utilisateur n’est pas valide, la fonction de validation renverra un message d’erreur. S’il n’y a pas d’erreurs, le validateur renverra un null.
- Dans cet exemple, nous créons un validateur qui garantit que TextFormField n’est pas vide. S’il est vide, il renverra un message d’erreur personnalisé.
-
Application
- Création d’une Application Flutter de Formulaire d’Inscription
- Dans ce travail, vous apprendrez à créer une application Flutter de formulaire d’inscription avec deux champs de texte dans la même ligne, un champ d’e-mail avec validation, un champ de mot de passe sécurisé, et une confirmation de mot de passe.
- Prérequis
- Avant de commencer, assurez-vous que Flutter est correctement installé sur votre ordinateur et que vous avez configuré votre environnement de développement.
- Étape 1 : Créez un nouveau projet Flutter
- Créez un nouveau projet Flutter dans votre environnement de développement, nommez votre projet et utilisez la commande Flutter appropriée pour le créer.
- Étape 2 : Configurez l’Interface Utilisateur
- Dans cette étape, nous allons concevoir l’interface utilisateur de l’application en utilisant une image de référence comme modèle visuel. Vous devez créer l’interface utilisateur pour le formulaire d’inscription en vous basant sur cette image.
- Image de Référence :
- L’image ci-dessus c’est une image de référence qui représente l’interface utilisateur souhaitée pour le formulaire d’inscription.
- Cette image servira de guide visuel pour créer la disposition et l’apparence de l’interface utilisateur.
- Conception de l’Interface Utilisateur :
- Utilisez l’image de référence pour créer les éléments de l’interface utilisateur, y compris les champs de texte pour le prénom, le nom, l’e-mail, le mot de passe, la confirmation de mot de passe, et le bouton de soumission.
- Respectez la disposition et le style présentés dans l’image.
- Structure du Formulaire :
- Assurez-vous que les champs de texte Prénom et Nom sont alignés côte à côte sur la même ligne.
- Les éléments du formulaire doivent être organisés de manière à correspondre à l’image de référence.
- Décorations des Champs de Texte :
- Appliquez les décorations appropriées aux champs de texte pour afficher les libellés et les styles conformément à l’image de référence.
- Validation :
- Assurez-vous d’ajouter la validation des champs de texte conformément aux critères précédemment mentionnés.
- Bouton de Soumission :
- Intégrez le bouton de soumission dans l’interface utilisateur conformément à l’image de référence.
- Test Visuel :
- Une fois la conception terminée, comparez votre interface utilisateur à l’image de référence pour vous assurer que tous les éléments correspondent visuellement.
- Étape 3 : Créez les Champs de Texte
- Ajoutez deux champs de texte (Prénom et Nom) sur la même ligne dans le formulaire en utilisant la classe TextFormField. Ajoutez des décorations aux champs de texte pour afficher des libellés.
- Étape 4 : Ajoutez la Validation des Champs de Texte
- Ajoutez une validation aux champs de texte pour vous assurer qu’ils ne sont pas vides. Assurez-vous que la validation fonctionne lorsque l’utilisateur commence à écrire.
- Étape 5 : Ajoutez un Champ d’E-mail
- Ajoutez un champ d’e-mail avec une validation spécifique en utilisant une expression régulière pour valider l’e-mail.
- Étape 6 : Ajoutez un Champ de Mot de Passe
- Ajoutez un champ de mot de passe sécurisé avec une validation spécifique. Assurez-vous que le mot de passe respecte les critères de validation (longueur, majuscules, minuscules, chiffres, caractères spéciaux).
- Étape 7 : Ajoutez une Confirmation de Mot de Passe
- Ajoutez un champ pour confirmer le mot de passe. Assurez-vous que la confirmation de mot de passe correspond au mot de passe saisi précédemment.
- Étape 8 : Gérez la Soumission du Formulaire
- Ajoutez un bouton de soumission au formulaire et gérez l’action lorsque le bouton est pressé. Vérifiez si le formulaire est valide avant de le soumettre.
- Étape 9 : Affichez les Données Saisies
- Affichez les données saisies par l’utilisateur dans la console lorsque le formulaire est soumis avec succès.
- Étape 10 : Testez l’Application
- Exécutez l’application Flutter pour la tester. Confirmez que les validations fonctionnent comme prévu en saisissant différentes données.
code utilisé dans la vidéo
Fichier main.dart
import 'package:flutter/material.dart';
import 'package:form_demo/tp_video/login_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Connexion Flutter',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const LoginPage(),
debugShowCheckedModeBanner: false,
);
}
}
Fichier login_page.dart
// Import du package Material Design de Flutter
import 'package:flutter/material.dart';
// Définition de la classe LoginPage qui est un StatefulWidget
// StatefulWidget car elle a un état qui peut changer (formulaire, chargement, etc.)
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
}
// Classe d'état qui gère la logique et l'interface de la page de connexion
class _LoginPageState extends State<LoginPage> {
// Clé pour identifier et valider le formulaire
// Permet d'accéder aux méthodes de validation du formulaire
final _formKey = GlobalKey<FormState>();
// Contrôleurs pour les champs de texte
// Permettent de lire/écrire dans les champs et de suivre leurs modifications
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
// Variables pour gérer l'état de l'interface
bool _isLoading = false; // Indique si la connexion est en cours
bool _obscurePassword = true; // Cache ou affiche le mot de passe
// ========== MÉTHODES DE VALIDATION ==========
// Valide le champ email
String? _validateEmail(String? value) {
// Vérifie si le champ est vide
if (value == null || value.isEmpty) {
return 'L\'email est obligatoire';
}
// Vérifie le format de l'email (présence de @)
if (!value.contains('@')) {
return 'L\'email doit contenir @';
}
// Retourne null si la validation réussit
return null;
}
// Valide le champ mot de passe
String? _validatePassword(String? value) {
// Vérifie si le champ est vide
if (value == null || value.isEmpty) {
return 'Le mot de passe est obligatoire';
}
// Vérifie la longueur minimale du mot de passe
if (value.length < 6) {
return 'Le mot de passe doit contenir au moins 6 caractères';
}
// Retourne null si la validation réussit
return null;
}
// ========== MÉTHODE DE CONNEXION ==========
// Gère le processus de connexion
void _login() async {
// Vérifie si tous les champs du formulaire sont valides
if (_formKey.currentState!.validate()) {
// Active l'état de chargement
setState(() {
_isLoading = true;
});
// Simulation d'un appel API avec un délai de 2 secondes
// En réalité, ici on ferait appel à une API d'authentification
await Future.delayed(const Duration(seconds: 2));
// Désactive l'état de chargement
setState(() {
_isLoading = false;
});
// Affiche un message de succès à l'utilisateur
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text(
'Connexion réussie !',
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.green, // Couleur de succès
duration: const Duration(seconds: 3), // Durée d'affichage
behavior: SnackBarBehavior.floating, // Style flottant
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), // Coins arrondis
),
),
);
// Optionnel : Navigation vers une autre page après connexion
// Décommentez ces lignes pour naviguer vers une page d'accueil
/*
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const HomePage()),
);
*/
}
}
// ========== GESTION DU CYCLE DE VIE ==========
@override
void dispose() {
// Nettoie les contrôleurs pour éviter les fuites de mémoire
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
// ========== CONSTRUCTION DE L'INTERFACE ==========
@override
Widget build(BuildContext context) {
return Scaffold(
// Fond gris clair pour toute la page
backgroundColor: Colors.grey[50],
body: SafeArea(
// SafeArea évite les zones non sécurisées (encoche, etc.)
child: Center(
child: SingleChildScrollView(
// Permet de scroller si le contenu dépasse l'écran
padding: const EdgeInsets.all(24.0), // Marge interne
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // Centre verticalement
children: [
// ========== LOGO/ICÔNE ==========
Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: Colors.blue.shade50, // Fond bleu très clair
shape: BoxShape.circle, // Forme circulaire
),
child: const Icon(
Icons.lock_outline, // Icône de cadenas
size: 40,
color: Colors.blue,
),
),
const SizedBox(height: 24), // Espacement
// ========== TITRE ==========
const Text(
'Connexion',
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const SizedBox(height: 8), // Petit espacement
// ========== SOUS-TITRE ==========
const Text(
'Connectez-vous à votre compte',
style: TextStyle(
fontSize: 16,
color: Colors.grey,
),
),
const SizedBox(height: 32), // Grand espacement
// ========== CARTE DU FORMULAIRE ==========
Container(
padding: const EdgeInsets.all(24), // Marge interne
decoration: BoxDecoration(
color: Colors.white, // Fond blanc
borderRadius: BorderRadius.circular(16), // Coins arrondis
boxShadow: [
// Ombre portée pour l'effet de relief
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Form(
key: _formKey, // Lien avec la clé du formulaire
child: Column(
children: [
// ========== CHAMP EMAIL ==========
TextFormField(
controller: _emailController, // Lie le contrôleur
decoration: InputDecoration(
labelText: 'Email', // Texte du label
prefixIcon: const Icon(Icons.email_outlined), // Icône gauche
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), // Coins arrondis
),
filled: true, // Active le remplissage
fillColor: Colors.grey[50], // Couleur de fond
),
keyboardType: TextInputType.emailAddress, // Clavier optimisé email
textInputAction: TextInputAction.next, // Bouton "suivant"
validator: _validateEmail, // Méthode de validation
onChanged: (_) {
// Met à jour l'interface à chaque frappe
setState(() {});
},
),
const SizedBox(height: 16), // Espacement entre champs
// ========== CHAMP MOT DE PASSE ==========
TextFormField(
controller: _passwordController, // Lie le contrôleur
decoration: InputDecoration(
labelText: 'Mot de passe',
prefixIcon: const Icon(Icons.lock_outline), // Icône cadenas
suffixIcon: IconButton(
// Bouton pour afficher/cacher le mot de passe
icon: Icon(
_obscurePassword
? Icons.visibility_off // Icône œil barré
: Icons.visibility, // Icône œil
color: Colors.grey,
),
onPressed: () {
setState(() {
_obscurePassword = !_obscurePassword; // Inverse l'état
});
},
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
filled: true,
fillColor: Colors.grey[50],
),
obscureText: _obscurePassword, // Cache le texte si true
textInputAction: TextInputAction.done, // Bouton "terminer"
validator: _validatePassword, // Méthode de validation
onChanged: (_) {
// Met à jour l'interface à chaque frappe
setState(() {});
},
onFieldSubmitted: (_) {
// Déclenche la connexion quand on appuie sur "terminer"
if (_formKey.currentState!.validate()) {
_login();
}
},
),
const SizedBox(height: 24), // Espacement avant le bouton
// ========== BOUTON DE CONNEXION ==========
SizedBox(
width: double.infinity, // Prend toute la largeur
height: 50,
child: ElevatedButton(
onPressed:
// Active le bouton seulement si le formulaire est valide
// ET qu'il n'y a pas de chargement en cours
_formKey.currentState?.validate() == true && !_isLoading
? _login // Appelle la méthode de connexion
: null, // Désactive le bouton
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue, // Couleur de fond
foregroundColor: Colors.white, // Couleur du texte
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), // Coins arrondis
),
elevation: 2, // Ombre du bouton
),
child: _isLoading
? // Affiche un indicateur de chargement si connexion en cours
const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
)
: // Sinon affiche le texte normal
const Text(
'Se connecter',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
const SizedBox(height: 16), // Espacement après le bouton
// ========== LIEN MOT DE PASSE OUBLIÉ ==========
TextButton(
onPressed: () {
// TODO: Implémenter la réinitialisation du mot de passe
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Fonctionnalité à implémenter'),
),
);
},
child: const Text(
'Mot de passe oublié ?',
style: TextStyle(
color: Colors.blue,
),
),
),
],
),
),
),
const SizedBox(height: 24), // Espacement après la carte
// ========== LIEN VERS INSCRIPTION ==========
Row(
mainAxisAlignment: MainAxisAlignment.center, // Centre horizontalement
children: [
const Text(
'Pas de compte ? ',
style: TextStyle(
color: Colors.grey,
),
),
GestureDetector(
onTap: () {
// TODO: Naviguer vers la page d'inscription
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Page d\'inscription à implémenter'),
),
);
},
child: const Text(
'Créer un compte',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.w600, // Texte plus gras
),
),
),
],
),
],
),
),
),
),
);
}
}
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyForm(),
);
}
}
class MyForm extends StatefulWidget {
@override
_MyFormState createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Formulaire de Validation'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
validator: (value) {
if (value == null || value.isEmpty) {
return 'Veuillez entrer du texte.';
}
return null;
},
decoration: InputDecoration(
labelText: 'Entrez votre nom d’utilisateur',
),
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// Si toutes les données sont correctes, enregistrez les données et traitez-les
// Vous pouvez ajouter votre logique de traitement ici
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Formulaire soumis avec succès'),
),
);
}
},
child: Text('Soumettre'),
),
],
),
),
),
);
}
}
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyForm(),
);
}
}
class MyForm extends StatefulWidget {
@override
_MyFormState createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Formulaire de Validation'),
),
body: Form(
key: _formKey,
autovalidateMode: AutovalidateMode.always, // Déclenche la validation dès le rendu
child: Column(
children: [
TextFormField(
validator: (value) {
if (value == null || value.isEmpty || value.length<12) {
return 'Veuillez entrer du texte.';
}
return null;
},
decoration: InputDecoration(
labelText: 'Entrez votre nom d’utilisateur',
),
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// Si toutes les données sont correctes, enregistrez les données et traitez-les
// Vous pouvez ajouter votre logique de traitement ici
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Formulaire soumis avec succès'),
),
);
}
},
child: Text('Soumettre'),
),
],
),
),
);
}
}
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyForm(),
);
}
}
class MyForm extends StatefulWidget {
@override
_MyFormState createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Formulaire de Validation'),
),
body: Form(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction, // Déclenche la validation lorsqu'un champ est modifié
child: Column(
children: [
TextFormField(
validator: (value) {
if (value == null || value.isEmpty|| value.length<12) {
return 'Veuillez entrer du texte.';
}
return null;
},
decoration: InputDecoration(
labelText: 'Entrez votre nom d’utilisateur',
),
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// Si toutes les données sont correctes, enregistrez les données et traitez-les
// Vous pouvez ajouter votre logique de traitement ici
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Formulaire soumis avec succès'),
),
);
}
},
child: Text('Soumettre'),
),
],
),
),
);
}
}
TextFormField(
autovalidateMode: AutovalidateMode.disabled,
),
```
RegExp _emailRegex = RegExp(r'^\S+@\S+$');
TextFormField(
validator: (value) {
if (!_emailRegex.hasMatch(value!)) {
return 'Adresse e-mail invalide';
}
return null;
},
),
```
Pour valider des champs dépendants l’un de l’autre, utilisez une variable d’état. Exemple avec un mot de passe et sa confirmation :
String? password;
TextFormField(
onChanged: (value) {
setState(() {
password = value;
});
},
),
TextFormField(
validator: (value) {
if (value != password) {
return 'Les mots de passe ne correspondent pas';
}
return null;
},
),
```
Parfois, vous voudrez peut-être valider des champs en faisant un appel API. Dans ce cas, il faudra gérer les erreurs retournées par l’API et les afficher sous le champ concerné.
bool isEmailAlreadyRegistered = false;
ElevatedButton(
onPressed: () async {
if (_formKey.currentState!.validate()) {
// Appel API
if (/*email déjà enregistré*/) {
setState(() {
isEmailAlreadyRegistered = true;
});
}
}
},
),
TextFormField(
onChanged: (value) {
if (isEmailAlreadyRegistered) {
setState(() {
isEmailAlreadyRegistered = false;
});
}
},
decoration: InputDecoration(
errorText: isEmailAlreadyRegistered ? 'E-mail déjà enregistré' : null,
),
),
```
Si vous ne souhaitez pas utiliser l’apparence Material pour vos champs, vous pouvez toujours utiliser `TextFormField` et le personnaliser avec la propriété `decoration`.
TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Votre texte',
),
),
```
RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()]).{8,12}$'))
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
// Construire un widget Formulaire (Form) en utilisant le _formKey créé ci-dessus.
return Form(
key: _formKey,
child: Column(
children: <Widget>[
// Ajouter des TextFormFields et ElevatedButton ici.
]
)
);
}
TextFormField(
// Le validateur reçoit le texte que l'utilisateur a saisi.
validator: (value) {
if (value.isEmpty) {
return 'Veuillez saisir du texte';
}
return null;
},
);
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// If the form is valid, display a Snackbar.
//Scaffold.of(context).showSnackBar(SnackBar(content: Text('Data is in processing.')));
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text(
"Saisissez ici quelque chose à afficher sur le snack-bar")));
}
},
child: const Text('Submit'),
)),


Solution
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(debugShowCheckedModeBanner: false,
home: MyForm(),
);
}
}
class MyForm extends StatefulWidget {
@override
_MyFormState createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
final _formKey = GlobalKey<FormState>();
String _firstName = '';
String _lastName = '';
String _email = '';
String _password = '';
String _confirmPassword = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Formulaire d\'inscription'),
),
body: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Row(
children: [
Expanded(
child: TextFormField(
decoration: InputDecoration(labelText: 'Prénom'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Veuillez entrer votre prénom.';
}
return null;
},
onChanged: (value) {
setState(() {
_firstName = value;
});
},
),
),
SizedBox(width: 16),
Expanded(
child: TextFormField(
decoration: InputDecoration(labelText: 'Nom'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Veuillez entrer votre nom.';
}
return null;
},
onChanged: (value) {
setState(() {
_lastName = value;
});
},
),
),
],
),
TextFormField(
decoration: InputDecoration(labelText: 'E-mail'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Veuillez entrer votre adresse e-mail.';
} else if (!value.contains('@')) {
return 'Adresse e-mail invalide.';
}
return null;
},
onChanged: (value) {
setState(() {
_email = value;
});
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Mot de passe'),
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Veuillez entrer un mot de passe.';
}
if (value.length < 8 || value.length > 12) {
return 'Le mot de passe doit contenir entre 8 et 12 caractères.';
}
if (!value.contains(RegExp(r'[a-z]'))) {
return 'Le mot de passe doit contenir au moins une lettre minuscule.';
}
if (!value.contains(RegExp(r'[A-Z]'))) {
return 'Le mot de passe doit contenir au moins une lettre majuscule.';
}
if (!value.contains(RegExp(r'[0-9]'))) {
return 'Le mot de passe doit contenir au moins un chiffre.';
}
if (!value.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]'))) {
return 'Le mot de passe doit contenir au moins un caractère spécial.';
}
return null;
},
onChanged: (value) {
setState(() {
_password = value;
});
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Confirmer le mot de passe'),
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Veuillez confirmer votre mot de passe.';
} else if (value != _password) {
return 'Les mots de passe ne correspondent pas.';
}
return null;
},
onChanged: (value) {
setState(() {
_confirmPassword = value;
});
},
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
print('Prénom : $_firstName');
print('Nom : $_lastName');
print('E-mail : $_email');
print('Mot de passe : $_password');
}
},
child: Text('Soumettre'),
),
],
),
),
),
);
}
}
