Créer et valider un formulaire avec Flutter
Sommaire
- 1- Objectif
- 2- Présentation
- 3- Créer un formulaire
- 3.1- Créer un formulaire avec une clé globale (
GlobalKey
) - 3.1.1- Définition d'une
GlobalKey
- 3.1.2- Exemple
- 3.1.3- Explication du code
- 3.2- Création d'un formulaire avec validation
- 3.2.1- Exemple
- 3.2.2- Explication du code
- 4- Applications
- 4.1- App-01
- 4.1.1- Travail demandé
- 4.2- App-02
- 4.2.1- Travail demandé
- 4.3- App-03
- 4.3.1- Travail demandé
- 4.3.2- Cours Flutter
Créer et valider un formulaire avec Flutter
-
Objectif
- Dans ce tutoriel flutter, nous allons apprendre à créer et valider un formulaire avec Flutter.
-
Présentation
- Les formulaires sont désormais un élément essentiel de toute application mobile ou Web. Les formulaires sont utilisés pour recueillir des informations auprès de l’utilisateur.
- Selon vos besoins, vos exigences et votre logique, vous pouvez créer un formulaire pour l’utilisateur, y compris l’authentification de l’utilisateur, la recherche, la commande, le filtrage, la réservation, etc.
- Le formulaire peut comporter des champs de texte, des cases à cocher et des boutons radio.
- Les formulaires font partie intégrante de toutes les applications mobiles et Web modernes.
- Il est utilisé pour recueillir des informations auprès des utilisateurs.
- Dans Flutter le widget Form agit comme un conteneur pour regrouper et valider plusieurs champs de formulaire.
- Lors de la création du formulaire, fournissez un fichier
GlobalKey
. Cela identifie de manière unique le Formet permet la validation du formulaire dans une étape ultérieure. - Le widget form utilise le widget enfant TextFormField pour permettre aux utilisateurs de saisir le champ de texte. Ce widget affiche un champ de texte de conception de matériau et nous permet également d’afficher les erreurs de validation lorsqu’elles se produisent.
-
Créer un formulaire
- Un widget de
form
est fourni par flutter pour créer des formulaires. - Il agit comme un conteneur, ce qui nous permet de regrouper plusieurs champs de formulaire.
- Le widget de form agit comme un conteneur, ce qui nous permet de regrouper et de valider les multiples champs du formulaire.
- Lorsque vous créez un formulaire, il est nécessaire de fournir le
GlobalKey
. Cette clé identifie le formulaire de manière unique et vous permet d’effectuer toute validation dans les champs du formulaire. -
Créer un formulaire avec une clé globale (
GlobalKey
) - Pour créer un formulaire et pour commencer nous devons fournir une clé globale (
GlobalKey
). -
Définition d’une
GlobalKey
- Avant tout 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 sesState
et Widget.final _formKey = GlobalKey
(); - 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
GlobalKey
est 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. -
Exemple
-
Explication du code
- Tout d’abord une classe personnalisée de nom MonFormulaire est créée.
- Ensuite une clé globale est définie à l’intérieur de cette classe avec le nom
_formKey
, qui contient FormState, utilisé pour recevoir les widgets de formulaire (Form). - Certains styles personnalisés se trouvent également dans la méthode Build de cette classe et utilisent le périphérique
TextFormField
pour fournir des champs de formulaire tels que le nom, le numéro de téléphone, la date de naissance ou simplement un champ standard. - InputDecoration est utilisé dans TextFormField pour styliser votre formulaire en modifiant les propriétés telles que les bordures, les étiquettes, les icônes, les conseils, les styles, etc.
- Enfin, nous avons ajouté un bouton pour soumettre le formulaire.
-
Création d’un formulaire avec validation
1-
Validation avec déclencheurs- Les trois étapes suivantes doivent être suivies pour créer un formulaire de validation dans Flutter.
- Étape 1 : Tout d’abord, utilisez le widget de formulaire avec la clé globale.
- Étape 2 : Puis, utilisez TextFormField pour fournir au champ de saisie une propriété de validation.
- Étape 3 : Enfin créez un bouton qui, lorsqu’il est cliqué, valide les champs du formulaire flutter, et s’il y a une erreur, il l’affiche.
-
Exemple
-
Explication du code
- Pour valider les propriétés d’entrée, nous avons utilisé
validator()
dans TextFormField. Chaque fois que l’utilisateur saisit la mauvaise entrée, la fonction validator() renvoie une chaîne contenant un message d’erreur ; sinon, il renvoie une valeur nulle . - Cela doit être assuré que le TextFormField n’a pas besoin d’être vide ; sinon, il renverra un message d’erreur.
2-
Validation avecautovalidate
- Dans Flutter, la validation automatique fait généralement référence à la validation automatique des entrées utilisateur dans les champs de formulaire lorsque l’utilisateur interagit avec eux, sans nécessiter de déclencheurs de validation explicites tels que la soumission d’un formulaire ou l’appui sur un bouton « valider ».
- Flutter fournit un cadre flexible pour la création de formulaires et la validation. Pour obtenir une validation automatique dans Flutter, vous pouvez suivre ces étapes :
- **Étape 1 : Création du projet**
- 1. Créez un nouveau projet Flutter dans votre environnement de développement (par exemple, avec Flutter CLI ou dans un IDE comme VSCode ou Android Studio).
- **Étape 2 : Structure de base de l’application**
- 2. Dans le fichier `main.dart`, créez une application Flutter de base avec une barre de navigation, un titre et un corps.
- **Étape 3 : Ajout de TextFormFields**
- 3. Dans le corps de l’application, ajoutez deux `
TextFormField
`. - 4. Pour chaque `
TextFormField
`, ajoutez le texte d’invite (`hintText
`) pour indiquer ce que l’utilisateur doit saisir. - **Étape 4 : Activation de la validation automatique**
- 5. Pour activer la validation automatique, définissez `
autovalidateMode
` sur `AutovalidateMode.always
` dans le widget `Form
` qui englobe les `TextFormField
`. - **Étape 5 : Validation de l’e-mail**
- 6. Pour le premier `
TextFormField
`, ajoutez une validation de l’e-mail en utilisant `validator
`. - 7. Utilisez une expression régulière pour valider l’e-mail.
- 8. Si l’e-mail n’est pas valide, retournez un message d’erreur.
- **Étape 6 : Validation du mot de passe**
- 9. Pour le deuxième `
TextFormField
`, ajoutez une validation de mot de passe. - 10.Vérifiez la longueur du mot de passe, la présence de minuscules, de majuscules, de chiffres et de caractères spéciaux.
- 10.1.Vérifiez que la longueur du mot de passe est comprise entre 8 et 12 caractères.
- 10.2.Assurez-vous que le mot de passe contient au moins une lettre minuscule (a-z).
- 10.3.Assurez-vous que le mot de passe contient au moins une lettre majuscule (A-Z).
- 10.4.Assurez-vous que le mot de passe contient au moins un chiffre (0-9).
- 10.5.Assurez-vous que le mot de passe contient au moins un caractère spécial (par exemple, !@#$%^&*()).
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.'; } // Continuez avec les autres vérifications... },
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.'; }
- 11. Si le mot de passe ne respecte pas les critères de validation, retournez un message d’erreur.
- **Étape 7 : Ajout de l’icône pour afficher/masquer le mot de passe**
- 12. À l’intérieur du
TextFormField
pour le mot de passe, ajoutez unsuffixIcon
avec unGestureDetector
et une icône (par exemple, une icône « œil »). - 13.Utilisez un état (par exemple,
_obscurePassword
) pour suivre si le mot de passe doit être masqué ou non. - 14.Lorsque l’utilisateur clique sur l’icône, utilisez
setState
pour inverser l’état_obscurePassword
. - 15.Utilisez
_obscurePassword
comme valeur pour la propriétéobscureText
duTextFormField
pour masquer ou afficher le mot de passe en fonction de l’état. - **Étape 8 : Soumission du formulaire**
- 16. Ajoutez un bouton «
Submit
» en bas du formulaire. - 17. Lorsque le bouton «
Submit
» est cliqué, vérifiez si le formulaire est valide en utilisant `_formKey.currentState.validate()
`. - 18. Si le formulaire est valide, affichez un message de confirmation. Sinon, les messages d’erreur seront automatiquement affichés sous les champs de texte invalides.
- En suivant ces étapes, vos apprenants pourront créer une application Flutter avec la validation automatique des champs de texte pour l’e-mail et le mot de passe. Assurez-vous de leur fournir le code d’exemple pour chaque étape et de les encourager à expérimenter et à comprendre comment chaque partie fonctionne
-
Applications
-
App-01
-
Travail demandé
- Pour commencer, créer une page de connexion simple contenant les champs suivants :
- Nom & Prénom
- Numéro de téléphone
- Mot de passe
- Pour la validation, nous souhaitons que les utilisateurs de notre application remplissent les informations correctes dans chacun de ces champs. La logique sera définie comme telle :
- Tout d’abord, pour le champ du nom, nous souhaitons que l’utilisateur saisisse un prénom et un nom de famille valides, qui peuvent être accompagnés d’initiales.
- Pour le champ email, nous voulons un email valide qui contient quelques caractères avant le signe « @ », ainsi que le domaine email à la fin de l’email.
- Ensuite pour la validation du numéro de téléphone, l’utilisateur doit saisir 11 chiffres en commençant par le chiffre zéro.
- Enfin, pour la validation de notre mot de passe, nous attendons de l’utilisateur qu’il utilise une combinaison d’une lettre majuscule, d’une lettre minuscule, d’un chiffre et d’un caractère spécial.
- Ce n’est que lorsque la saisie de l’utilisateur correspond à ce qui précède que nous voulons accepter sa saisie avant de faire des demandes, telles que l’envoi à un serveur ou l’enregistrement dans une base de données.
-
App-02
-
Travail demandé
- Créez une application Flutter comme l’illustre le schéma suivant:
-
App-03
-
Travail demandé
- Vous allez implémenter une application Flutter simple qui affiche un écran de connexion. L’écran contient deux champs de texte : Email et mot de passe.
- Votre application doive être appliquée selon la conception spécifiée comme indiqué ci-dessous
Pour créer un formulaire avec Flutter, vous pouvez utiliser les widgets TextField pour les entrées de texte, DropdownButton pour les menus déroulants, Radio pour les boutons radio, Checkbox pour les cases à cocher, et ElevatedButton pour les boutons d’action.
```dart
autovalidateMode: AutovalidateMode.always,
```
Solution
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(debugShowCheckedModeBanner: false,
home: MyForm(),
);
}
}
class MyForm extends StatefulWidget {
const MyForm({super.key});
@override
_MyFormState createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
bool _obscurePassword = true; // Par défaut, le mot de passe est masqué
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Formulaire d\'autovalidation'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
autovalidateMode: AutovalidateMode.always,
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: TextFormField(
decoration: const InputDecoration(
labelText: 'Email',
hintText: 'Entrez votre adresse email',
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Veuillez entrer une adresse email.';
}
// Expression régulière pour la validation de l'adresse e-mail
const pattern = r'^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$';
final regex = RegExp(pattern);
if (!regex.hasMatch(value)) {
return 'Veuillez entrer une adresse email valide.';
}
return null;
},
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: TextFormField(
decoration: InputDecoration(
labelText: 'Password',
hintText: 'Entrez votre mot de passe',
suffixIcon: GestureDetector(
onTap: () {
setState(() {
_obscurePassword = !_obscurePassword;
});
},
child: Icon(
_obscurePassword
? Icons.visibility_off
: Icons.visibility,
),
),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Veuillez entrer un mot de passe.';
}
// Vérifier la longueur du mot de passe
if (value.length < 8 || value.length > 12) {
return 'Le mot de passe doit contenir entre 8 et 12 caractères.';
}
// Vérifier la présence d'au moins une minuscule
if (!value.contains(RegExp(r'[a-z]'))) {
return 'Le mot de passe doit contenir au moins une lettre minuscule.';
}
// Vérifier la présence d'au moins une majuscule
if (!value.contains(RegExp(r'[A-Z]'))) {
return 'Le mot de passe doit contenir au moins une lettre majuscule.';
}
// Vérifier la présence d'au moins un chiffre
if (!value.contains(RegExp(r'[0-9]'))) {
return 'Le mot de passe doit contenir au moins un chiffre.';
}
// Vérifier la présence d'au moins un caractère spécial
if (!value.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]'))) {
return 'Le mot de passe doit contenir au moins un caractère spécial.';
}
return null;
},
obscureText: _obscurePassword,
),
),
ElevatedButton(
child: const Text('Submit'),
onPressed: () {
if (_formKey.currentState?.validate() == true) {
// Form is valid, process the data
// You can access form data using _formKey.currentState!.fields
}
},
),
],
),
),
),
);
}
}
Solution
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
AutovalidateMode _autoValidate = AutovalidateMode.disabled;
String? _name;
String? _mobile;
String? _email;
void _validateInputs() {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
} else {
setState(() {
_autoValidate = AutovalidateMode.always;
});
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Form Validation'),
),
body: SingleChildScrollView(
child: Container(
margin: const EdgeInsets.all(15.0),
child: Form(
key: _formKey,
autovalidateMode: _autoValidate,
child: formUI(),
),
),
),
),
);
}
Widget formUI() {
return Column(
children: <Widget>[
TextFormField(
decoration: const InputDecoration(labelText: 'Name'),
keyboardType: TextInputType.text,
validator: validateName,
onSaved: (String? val) {
_name = val;
},
),
TextFormField(
decoration: const InputDecoration(labelText: 'Mobile'),
keyboardType: TextInputType.phone,
validator: validateMobile,
onSaved: (String? val) {
_mobile = val;
},
),
TextFormField(
decoration: const InputDecoration(labelText: 'Email'),
keyboardType: TextInputType.emailAddress,
validator: validateEmail,
onSaved: (String? val) {
_email = val;
},
),
const SizedBox(
height: 10.0,
),
OutlinedButton(
onPressed: _validateInputs,
child: const Text('Validate'),
)
],
);
}
String? validateName(String? value) {
if (value!.isEmpty) {
return 'Name cannot be empty';
}
if (value.length < 3) {
return 'Name must be more than 2 charater';
} else {
return null;
}
}
String? validateMobile(String? value) {
if (value!.isEmpty) {
return 'Phone number cannot be empty';
}
if (value.length != 10) {
return 'Mobile Number must be of 10 digit';
} else {
return null;
}
}
String? validateEmail(String? value) {
String pattern =
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
RegExp regex = RegExp(pattern);
if (value!.isEmpty) {
return 'Email cannot be empty';
}
if (!regex.hasMatch(value)) {
return 'Enter Valid Email';
} else {
return null;
}
}
}
Solution
import 'package:flutter/material.dart';
void main() => runApp(MyWidget());
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Application Flutter',
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(title: const Text("Connexion")),
body: const LoginForm(),
),
);
}
}
class LoginForm extends StatefulWidget {
const LoginForm({super.key});
@override
_LoginFormState createState() => _LoginFormState();
}
class _LoginFormState extends State&<LoginForm> {
final _formKey = GlobalKey<FormState>();
String? _email, _password;
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(40, 10, 40, 0),
child: TextFormField(
validator: (input) {
if (input!.isEmpty) {
return 'Entrer une adresse email valide';
}
return null;
},
onSaved: (input) => _email = input!,
decoration: const InputDecoration(labelText: 'Email'),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(40, 6, 40, 0),
child: TextFormField(
validator: (input) {
if (input!.length < 6) {
return 'Le mot de passe doit contenir au moins 6 caractères';
}
},
onSaved: (input) => _password = input!,
decoration: const InputDecoration(labelText: 'Mot de passe'),
obscureText: true,
),
),
Padding(
padding: const EdgeInsets.fromLTRB(40, 6, 40, 10),
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
// Appel API de connexion avec _email et _password
}
},
child: const Text('Se connecter'),
),
),
],
),
);
}
}
Solution
import 'package:flutter/material.dart';
void main() => runApp(MyWidget());
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Valider Formulaire',
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(title: const Text("Connexion")),
body: const ValiderFormulaire(),
),
);
}
}
class ValiderFormulaire extends StatefulWidget {
const ValiderFormulaire({super.key});
@override
_ValiderFormulaireState createState() => _ValiderFormulaireState();
}
class _ValiderFormulaireState extends State<ValiderFormulaire> {
final _formKey = GlobalKey<FormState>();
bool _accepterCGU = false;
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Container(
child: Padding(
padding: const EdgeInsets.fromLTRB(40, 4, 40, 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
decoration: const InputDecoration(labelText: 'Nom'),
validator: (value) {
if (value!.isEmpty) {
return 'Veuillez saisir votre nom';
}
return null;
},
),
CheckboxListTile(
title: const Text('J\'accepte les CGU'),
value: _accepterCGU,
onChanged: (value) {
setState(() {
_accepterCGU = value!;
});
},
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Données en cours')));
}
},
child: const Text('Submit'),
),
],
),
),
),
);
}
}