Formulaires et validation dans Ionic React

Publié: 2022-03-10
Résumé rapide ↬ Ionic Framework fournit un support de premier ordre pour la création d'applications rapides et optimisées pour les mobiles pour toute plate-forme utilisant React. Dans ce didacticiel, vous apprendrez à créer des formulaires lorsque vous travaillez avec Ionic React et à rendre ces formulaires interactifs en ajoutant des règles de validation avec des conseils de texte utiles.

Ionic Framework est une boîte à outils d'interface utilisateur permettant de créer des applications mobiles multiplateformes à l'aide de HTML, CSS et JavaScript. La sortie d'Ionic 5 au début de 2020 est accompagnée d'un support officiel pour React, permettant aux développeurs de React de créer facilement des applications mobiles à l'aide de leurs outils préférés. Cependant, il n'y a pas beaucoup de support pour travailler avec des formulaires, et de nombreuses bibliothèques existantes disponibles pour créer des formulaires dans l'écosystème React ne fonctionnent pas bien avec les composants d'Ionic Framework.

Vous apprendrez à créer des formulaires à l'aide des composants d'entrée de l'interface utilisateur d'Ionic React dans ce didacticiel. Vous apprendrez également à utiliser une bibliothèque pour aider à détecter les changements d'entrée de formulaire et à répondre aux règles de validation. Enfin, vous apprendrez à rendre vos formulaires accessibles aux lecteurs d'écran en ajoutant du texte utile aux attributs ARIA de vos entrées.

Composants de formulaire d'Ionic

Les formulaires sont aujourd'hui une partie importante de la plupart des applications Web et mobiles. Que vous autorisiez l'accès à des parties restreintes de votre application via des formulaires d'inscription et de connexion des utilisateurs ou que vous recueilliez les commentaires de vos utilisateurs, vous devez, à un moment donné du cycle de vie de votre application, créer un formulaire.

Ionic fournit des composants prédéfinis pour travailler avec des formulaires, dont certains incluent IonItem , IonLabel , IonInput , IonCheckbox et IonRadio . Nous pouvons combiner ces composants pour créer des formulaires d'aspect standard sans ajouter de style nous-mêmes.

Par exemple, le code suivant :

 <form className="ion-padding"> <IonItem> <IonLabel position="floating">Username</IonLabel> <IonInput /> </IonItem> <IonItem> <IonLabel position="floating">Password</IonLabel> <IonInput type="password" /> </IonItem> <IonItem lines="none"> <IonLabel>Remember me</IonLabel> <IonCheckbox defaultChecked={true} slot="start" /> </IonItem> <IonButton className="ion-margin-top" type="submit" expand="block"> Login </IonButton> </form>

Nous donnera un formulaire de connexion qui ressemble à ceci :

Formulaire de connexion standard sur iOS ( Grand aperçu )

Prêts à l'emploi, les composants de formulaire d'Ionic ont fière allure sur iOS ou Android, mais ils peuvent être un peu difficiles à manier si vous travaillez avec React. Comme avec la plupart des outils de l'écosystème React, vous devez décider de la manière dont vous souhaitez créer vos formulaires en termes de fonctionnalité et d'accessibilité, toutes deux tout aussi importantes que la conception.

Bien qu'il existe déjà de nombreux assistants de formulaire React parmi lesquels choisir, la plupart d'entre eux ne fonctionnent pas avec les composants de formulaire d'Ionic. Je soupçonne que la raison principale en est que l'événement déclenché lorsqu'une valeur de champ change dans Ionic est onIonChange , alors que la plupart des bibliothèques de formulaires existantes écoutent onChange .

Modifier l'événement déclenché lorsque le champ change ( Grand aperçu )

React Hook Form: bibliothèque de formulaires React petits et rapides

Heureusement, tout n'est pas catastrophique. Je suis récemment tombé sur React Hook Form (RHF), une bibliothèque permettant de travailler avec des formulaires dans des projets React. Il prend en charge les composants contrôlés ou non et la validation des entrées, et l'API est basée sur des crochets, elle ne fonctionne donc qu'avec des composants fonctionnels.

La fonctionnalité la plus attrayante pour les développeurs Ionic React - à mon avis - est le composant wrapper <Controller /> qu'il fournit pour travailler avec des composants contrôlés. Le composant a un prop onChangeName qui peut être utilisé pour spécifier le nom de l'événement de changement pour n'importe quelle instance de composant que vous lui transmettez. Je vais vous montrer comment cela facilite vraiment le travail avec les formulaires dans Ionic dans les sections suivantes.

Plus après saut! Continuez à lire ci-dessous ↓

Créer un formulaire d'inscription

Voyons comment RHF nous aide avec la fonctionnalité de formulaire lorsque nous créons un formulaire d'inscription dans Ionic. Si vous exécutez la dernière version de la CLI Ionic (exécutez npm i -g @ionic/cli pour confirmer), démarrez une nouvelle application Ionic avec React en exécutant la commande suivante :

 ionic start myApp blank --type=react

J'ai utilisé un modèle vierge ici. Vous devriez pouvoir réécrire vos formulaires existants pour utiliser facilement la bibliothèque React Hook Form, en particulier si vos composants sont écrits en tant que composants fonctionnels.

Remarque : Vous devez supprimer le composant ExploreContainer et son importation dans Home.tsx avant de poursuivre ce didacticiel.

Pour commencer avec votre formulaire, installez le package React Hook Form en exécutant la commande suivante dans le répertoire racine de votre projet :

 yarn add react-hook-form

Cela rendra la bibliothèque React Hook Form disponible dans votre projet. Créons un champ de saisie de formulaire à l'aide de la bibliothèque. Ouvrez le fichier Home.tsx et remplacez son contenu par ce qui suit :

 import { IonContent, IonPage, IonText, IonItem, IonLabel, IonInput, IonButton } from "@ionic/react"; import React from "react"; import "./Home.css"; import { Controller, useForm } from 'react-hook-form'; const Home: React.FC = () => { const { control, handleSubmit } = useForm(); const registerUser = (data) => { console.log('creating a new user account with: ', data); } return ( <IonPage> <IonContent className="ion-padding"> <IonText color="muted"> <h2>Create Account</h2> </IonText> <form onSubmit={handleSubmit(registerUser)}> <IonItem> <IonLabel position="floating">Email</IonLabel> <Controller as={<IonInput type="email" />} name="email" control={control} onChangeName="onIonChange" /> </IonItem> <IonButton expand="block" type="submit" className="ion-margin-top"> Register </IonButton> </form> </IonContent> </IonPage> ); }; export default Home;

Cela vous donne un formulaire avec un seul champ pour collecter une adresse e-mail. Décomposons les parties importantes (mises en évidence dans le bloc de code).

Tout d'abord, nous déstructurons la valeur de retour du crochet useForm() de RHF. handleSubmit transmet les valeurs de votre entrée à la fonction de gestionnaire que vous spécifiez lorsque le formulaire passe la validation. control est un objet contenant des méthodes utilisées pour enregistrer les composants contrôlés dans RHF.

Ensuite, nous avons un bloc d'élément de formulaire standard, mais contrairement à l'exemple du formulaire de connexion, nous passons le composant IonInput au composant <Controller /> de RHF, enregistrons l'événement de modification en définissant la propriété onChangeName de <Controller / <Controller /> sur l'événement de modification d'Ionic. name et définissez la prop de control sur l'objet de contrôle en invoquant useForm() .

C'est bien jusqu'à présent, mais vous pourriez vous retrouver à répéter presque le même code encore et encore. Vous pouvez essayer de créer un composant Input réutilisable qui crée un champ de saisie avec des propriétés données.

Créez un fichier dans le répertoire src/components nommé Input.tsx et ajoutez le code suivant au fichier :

 import React, { FC } from "react"; import { IonItem, IonLabel, IonInput } from "@ionic/react"; import { Controller, Control } from "react-hook-form"; export interface InputProps { name: string; control?: Control; label?: string; component?: JSX.Element; } const Input: FC<InputProps> = ({ name, control, component, label, }) => { return ( <> <IonItem> {label && ( <IonLabel position="floating">{label}</IonLabel> )} <Controller as={component ?? <IonInput />} name={name} control={control} onChangeName="onIonChange" /> </IonItem> </> ); }; export default Input;

Ce composant reçoit un accessoire de name et des accessoires facultatifs control , component et d' label et affiche un champ de saisie à l'aide des composants de forme ionique présentés précédemment. Cela réduit la quantité de code que vous devez écrire lors de la création de champs de saisie de formulaire. Vous pouvez terminer le reste de votre formulaire en utilisant ce composant. Modifiez le fichier Home.tsx avec les modifications suivantes :

 import { IonContent, IonPage, IonText, IonInput, IonButton, IonCheckbox, IonItem, IonLabel } from "@ionic/react"; import React from "react"; import "./Home.css"; import { useForm } from "react-hook-form"; import Input, { InputProps } from "../components/Input"; const Home: React.FC = () => { const { control, handleSubmit } = useForm(); const formFields: InputProps[] = [ { name: "email", component: <IonInput type="email" />, label: "Email", }, { name: "fullName", label: "Full Name", }, { name: "password", component: <IonInput type="password" clearOnEdit={false} />, label: "Password", }, ]; const registerUser = (data) => { console.log("creating a new user account with: ", data); }; return ( <IonPage> <IonContent> <div className="ion-padding"> <IonText color="muted"> <h2>Create Account</h2> </IonText> <form onSubmit={handleSubmit(registerUser)}> {formFields.map((field, index) => ( <Input {...field} control={control} key={index} /> ))} <IonItem> <IonLabel>I agree to the terms of service</IonLabel> <IonCheckbox slot="start" /> </IonItem> <IonButton expand="block" type="submit" className="ion-margin-top"> Register </IonButton> </form> </div> </IonContent> </IonPage> ); }; export default Home;

Avec votre configuration jusqu'à présent, vous disposez d'un tableau des champs de saisie de votre formulaire (le name est la seule propriété requise), chaque champ étant rendu à l'aide du composant Input du précédent. Vous pouvez aller encore plus loin et avoir vos données de champ dans un fichier JSON, en gardant le code dans vos composants avec des formulaires propres. À ce stade, votre application (s'exécutant sur https://localhost:8100 avec la commande ionic serve ) devrait ressembler à ceci :

Page du formulaire d'inscription (iOS) ( Grand aperçu )

Qu'en est-il de la validation sur le terrain ?

Vous avez peut-être remarqué que les champs de saisie de notre formulaire n'ont pas encore de logique de validation. S'il s'agissait d'une application destinée à une utilisation dans le monde réel, cela pourrait entraîner de nombreux effets indésirables à moins que votre API ne soit configurée pour valider les données entrantes. D'ailleurs, votre API doit toujours valider les données entrantes.

RHF est livré avec une validation qui s'aligne sur la norme HTML pour la validation de formulaire intégrée. Cela fonctionne très bien pour une validation simple comme rendre un champ obligatoire ou définir des longueurs de champ minimales et maximales. Si vous souhaitez utiliser une logique de validation complexe, je vous recommande d'utiliser Yup. Bien que vous puissiez utiliser n'importe quelle bibliothèque de validation de schéma d'objet, RHF prend en charge Yup prêt à l'emploi.

Exécutez la commande suivante pour installer la bibliothèque (et les typages) :

 yarn add yup @types/yup

Ensuite, ajoutez ceci aux importations de votre composant :

 import { object, string } from 'yup'; const Home: React.FC = () => { ... }

Ajoutez ensuite le code suivant en haut de votre composant :

 const Home: React.FC = () => { const validationSchema = object().shape({ email: string().required().email(), fullName: string().required().min(5).max(32), password: string().required().min(8), }); // ... }

Ici, nous avons créé un schéma d'objet et ajouté des règles de validation à chaque propriété à l'aide de yup . Les noms de l'objet doivent correspondre aux noms des balises d'entrée de votre formulaire, sinon vos règles ne seront pas déclenchées.

Enfin, mettez à jour votre crochet useForm() pour utiliser le schéma que nous avons défini en définissant la propriété validationSchema comme ceci :

 const { control, handleSubmit } = useForm({ validationSchema, });

Désormais, lorsque vous cliquez sur le bouton Soumettre, le gestionnaire handleSubmit n'est pas appelé et les données du formulaire ne sont pas soumises. Bien que ce soit exactement ce que nous voulions, il semble que l'utilisateur n'ait aucun moyen de savoir ce qui se passe. Corrigeons cela en affichant des conseils de texte lorsqu'un champ n'est pas rempli correctement.

Tout d'abord, mettez à jour le composant Input pour qu'il ressemble à ceci :

 import React, { FC } from "react"; import { IonItem, IonLabel, IonInput, IonText } from "@ionic/react"; import { Controller, Control, NestDataObject, FieldError } from "react-hook-form"; export interface InputProps { name: string; control?: Control; label?: string; component?: JSX.Element; errors?: NestDataObject<Record<string, any>, FieldError>; } const Input: FC<InputProps> = ({ name, control, component, label, errors, }) => { return ( <> <IonItem> {label && <IonLabel position="floating">{label}</IonLabel>} <Controller as={component ?? <IonInput />} name={name} control={control} onChangeName="onIonChange" /> </IonItem> {errors && errors[name] && ( <IonText color="danger" className="ion-padding-start"> <small>{errors[name].message}</small> </IonText> )} </> ); }; export default Input;

Ici, nous avons mis à jour notre composant pour recevoir une propriété facultative supplémentaire qui est l'objet d'erreur de RHF, et nous affichons un message d'erreur dans le champ d'entrée renvoyé chaque fois qu'il y a une erreur. Une dernière chose, ajoutez l'objet errors à votre objet déstructuré et mettez à jour le composant dans votre boucle :

 const { control, handleSubmit, errors } = useForm({ validationSchema, });
 {formFields.map((field, index) => ( <Input {...field} control={control} key={index} errors={errors} /> ))}
Formulaire d'inscription avec messages d'erreur (iOS) ( Grand aperçu )

Vos formulaires fournissent désormais des repères visuels lorsqu'un utilisateur ne fait pas quelque chose correctement. Yup vous permet de changer le message d'erreur. Vous pouvez le faire en transmettant une chaîne à la méthode de validation que vous utilisez. Pour le courrier électronique, par exemple, vous pouvez effectuer les opérations suivantes :

 { email: string() .email('Please provide a valid email address') .required('This is a required field'), }

Améliorer l'accessibilité

Les composants d'Ionic sont généralement des wrappers sur l'élément natif correspondant, ce qui signifie qu'ils acceptent la plupart, sinon la totalité, des attributs existants de cet élément. Vous pouvez améliorer vos champs de saisie et les rendre plus accessibles aux utilisateurs malvoyants en définissant des attributs ARIA avec du texte pertinent.

Pour continuer avec notre exemple de formulaire d'inscription, ouvrez le fichier Input.tsx et apportez les modifications suivantes :

 import React, { FC } from "react"; import { IonItem, IonLabel, IonInput, IonText } from "@ionic/react"; import { Controller, Control, NestDataObject, FieldError } from "react-hook-form"; export interface InputProps { name: string; control?: Control; label?: string; component?: JSX.Element; errors?: NestDataObject<Record<string, any>, FieldError>; } const Input: FC<InputProps> = ({ name, control, component, label, errors, }) => { return ( <> <IonItem> {label && <IonLabel position="floating">{label}</IonLabel>} <Controller as={ component ?? ( <IonInput aria-invalid={errors && errors[name] ? "true" : "false"} aria-describedby={`${name}Error`} /> ) } name={name} control={control} onChangeName="onIonChange" /> </IonItem> {errors && errors[name] && ( <IonText color="danger" className="ion-padding-start"> <small> <span role="alert" id={`${name}Error`}> {errors[name].message} </span> </small> </IonText> )} </> ); }; export default Input;

Le composant IonInput par défaut que nous transmettons à Controller inclut désormais un attribut aria-invalid pour indiquer si le champ contient une erreur, et un attribut aria-describedby dedicatedby pour pointer vers le message d'erreur correspondant. Le message d'erreur est maintenant entouré d'un span ayant un rôle ARIA défini sur "error". Désormais, lorsque votre champ contient une erreur, un lecteur d'écran mettra en surbrillance ce champ et lira le message d'erreur.

  • Vous trouverez le dépôt GitHub ici.

Conclusion

Toutes nos félicitations! Vous avez appris à créer et à valider des formulaires lors de la création d'applications multiplateformes à l'aide d'Ionic. Vous avez également vu à quel point il est facile de rendre vos champs de saisie accessibles aux utilisateurs malvoyants. J'espère que ce didacticiel fournit une plate-forme solide que vous pouvez utiliser lors de la création de formulaires dans vos applications Ionic React. Il existe d'autres composants pour la création de formulaires (tels que la sélection et les radios) que nous n'avons pas explorés dans ce didacticiel, mais vous pouvez trouver et en savoir plus à leur sujet dans la documentation officielle.

Les références

  • Documents sur le cadre ionique
  • Formulaire de crochet de réaction
  • Ouais Docs
  • Phil Haack sur la validation des adresses e-mail
  • Accessibilité sur MDN Web Docs