Gestion des formulaires

Introduction

Les formulaires occupent une place centrale dans les applications web, qu'il s'agisse de se connecter à un compte, de passer une commande ou encore de lancer une recherche. Ils permettent à l'utilisateur de fournir des informations que l'application doit ensuite exploiter. Avec Vue, il est possible de relier directement un champ de formulaire à une donnée JavaScript afin que toute modification de l'un se répercute automatiquement sur l'autre. Cette approche évite d'écrire du code répétitif et garantit une interface plus fluide.

La directive v-model

La directive v-model met en place une liaison réactive à double sens entre un champ de formulaire et une donnée JavaScript :

v-model fonctionne avec la plupart des champs standards et chaque type a son comportement spécifique. Par exemple, Les champs texte et radio renvoient une chaîne de caractères, une seule case à cocher renvoie un booléen, plusieurs cases à cocher renvoient un tableau, une liste à choix unique peut renvoyer une chaîne de caractères ou un tableau en mode multiple, etc.


                <script setup>
                import { ref } from 'vue'

                const prenom = ref('')

                // Petite fonction pour démontrer la synchronisation dans l'autre sens.
                const appliquerPrenomParDefaut = () => 
                {
                    prenom.value = 'Alice'
                }
                </script>

                <template>
                    <label for="prenom">Prénom</label>
                    <input id="prenom" type="text" v-model="prenom" placeholder="Entrez votre prénom">

                    <p>Valeur de la données réactive "prenom" : {{ prenom }}</p>

                    <!-- En cliquant, on modifie la donnée réactive depuis le code -->
                    <button type="button" @click="appliquerPrenomParDefaut">Appliquer prénom par défaut</button>
                </template>
            

Le champ et la variable prenom sont maintenant synchronisés automatiquement

Champ texte et zone de texte

On a déjà vu le principe avec un simple champ texte. Une zone de texte (<textarea>) fonctionne de la même manière, on lie la donnée avec v-model.


                    <script setup>
                    import { ref } from 'vue'

                    const sujet = ref('')
                    const message = ref('')
                    </script>

                    <template>
                        <label for="sujet">Sujet</label>
                        <input id="sujet" type="text" v-model="sujet" placeholder="Ex. Demande de devis">

                        <label for="message">Message</label>
                        <textarea id="message" v-model="message" rows="4" placeholder="Décrivez votre besoin"></textarea>

                        <p>Aperçu : {{ sujet }} — {{ message.length }} caractères</p>
                    </template>
                

La saisie met à jour les deux données réactives en direct et l'interface reflète ces valeurs sans code supplémentaire.

Boutons radio

Un groupe de boutons radio permet de choisir une option parmi plusieurs. La donnée liée contient la valeur de l'option sélectionnée.


                    <script setup>
                    import { ref } from 'vue'

                    const modeLivraison = ref('standard')
                    </script>

                    <template>
                        <fieldset>
                            <legend>Mode de livraison</legend>

                            <label>
                            <input type="radio" value="standard" v-model="modeLivraison">
                            Standard (3 jours)
                            </label>

                            <label>
                                <input type="radio" value="express" v-model="modeLivraison">
                                Express (24 h)
                            </label>
                        </fieldset>

                        <p>Choix : {{ modeLivraison }}</p>
                    </template>
                

Les deux boutons partagent la même donnée. Une seule valeur est possible à la fois et modeLivraison reçoit la valeur du bouton coché.

Case à cocher

Case à cocher unique

Une case à cocher seule représente un booléen. La donnée liée avec v-model vaut true quand la case est cochée et false quand elle est décochée.


                <script setup>
                import { ref } from 'vue'

                const accepterConditions = ref(false)

                const basculerParCode = () => 
                {
                    accepterConditions.value = !accepterConditions.value
                }
                </script>

                <template>
                    <fieldset>
                        <legend>Conditions générales</legend>

                        <label>
                        <input type="checkbox" v-model="accepterConditions">
                            J'accepte les conditions générales
                        </label>

                        <p>État actuel {{ accepterConditions ? 'accepté' : 'non accepté' }}</p>

                        <button type="button" @click="basculerParCode">Basculer par code</button>
                    </fieldset>
                </template>
                

La case met à jour la donnée en temps réel et toute modification depuis le code s'affiche immédiatement. Ici, le bouton démontre la synchronisation dans l'autre sens.

Variante avec valeurs métier

Si l'on préfère stocker des valeurs ayant un sens pour l'application plutôt qu'un simple booléen, on peut utiliser :true-value et :false-value.


                <script setup>
                import { ref } from 'vue'

                // La constante 'statut' peut avoir comme valeur "accepted" ou "not_accepted".
                const statut = ref('not_accepted')
                </script>

                <template>
                    <label>
                        <input 
                            type="checkbox" 
                            v-model="statut" 
                            :true-value="'accepted'" 
                            :false-value="'not_accepted'"
                        >
                        Accepter la charte
                    </label>

                    <p>Statut {{ statut }}</p>
                </template>
                

Cette approche évite les conversions manuelles et reste entièrement réactive.

Cases à cocher multiples

Un groupe de cases à cocher alimente un tableau. La donnée liée contient la liste des valeurs cochées.


                    <script setup>
                    import { ref } from 'vue'

                    // Tableau des valeurs cochées.
                    const accessoires = ref([])
                    </script>

                    <template>
                        <fieldset>
                            <legend>Accessoires</legend>

                            <label>
                                <input type="checkbox" value="housse" v-model="accessoires">
                                Housse de protection
                            </label>

                            <label>
                                <input type="checkbox" value="garantie" v-model="accessoires">
                                Extension de garantie
                            </label>

                            <label>
                                <input type="checkbox" value="chargeur" v-model="accessoires">
                                Chargeur supplémentaire
                            </label>
                        </fieldset>

                        <p>Accessoires sélectionnés : {{ accessoires || 'aucun' }}</p>
                    </template>
                

Cocher ajoute la valeur dans le tableau. Décocher la retire. L'ordre d'affichage est indépendant de l'ordre dans le tableau.

Listes déroulantes

Une liste simple renvoie une valeur unique.


                    <script setup>
                    import { ref } from 'vue'

                    // Donnée de référence liée à la balise "select".
                    const pays = ref('be')
                    </script>

                    <template>
                        <label for="pays">Pays</label>
                        <select id="pays" v-model="pays">
                            <option value="be">Belgique</option>
                            <option value="fr">France</option>
                            <option value="nl">Pays-Bas</option>
                        </select>

                        <p>Pays sélectionné : {{ pays }}</p>
                    </template>
                

Une liste en mode multiple renvoie un tableau des valeurs sélectionnées.


                    <script setup>
                    import { ref } from 'vue'

                    // Donnée de référence liée à la balise "select".
                    const tags = ref([])
                    </script>

                    <template>
                        <label for="tags">Tags</label>
                        <!-- L'attribut mutliple permet de sélectionner plusieurs options. -->
                        <select id="tags" multiple v-model="tags">
                            <option value="audio">Audio</option>
                            <option value="clavier">Clavier</option>
                            <option value="souris">Souris</option>
                        </select>

                        <p>Tag(s) sélectionné(s) : {{ tags }}</p>
                    </template>
                

Modificateurs utiles

Les modificateurs de v-model permettent d'ajuster la valeur saisie avant qu'elle ne soit stockée dans la donnée réactive :


                    <script setup>
                    import { ref } from 'vue'

                    const quantite = ref(1)
                    const recherche = ref('')
                    const email = ref('')
                    </script>

                    <template>
                        <label>Quantité</label>
                        <input type="text" v-model.number="quantite">

                        <label>Recherche</label>
                        <input type="search" v-model.trim="recherche" placeholder="Tapez un mot-clé">

                        <label>Email</label>
                        <input type="email" v-model.lazy="email" placeholder="votre@mail.com">

                        <ul>
                            <li>quantite : {{ quantite }} (de type "{{ typeof quantite }}")</li>
                            <li>recherche : {{ recherche }}</li>
                            <li>email : {{ email }}</li>
                        </ul>
                    </template>
                

Notez que les modificateurs peuvent se combiner selon le besoin, par exemple v-model.trim.number.

Exercices

Créer un nouveau projet Vue nommé vuejs04-gestion-des-formulaires en suivant la procédure décrite dans le chapitre dédié. Tous les exercices de cette page peuvent être réalisés dans ce projet, directement les uns à la suite des autres dans le fichier App.vue.

Dans la partie template, créer une balise <h1> avec le texte suivante : "Vue.js 04 : Gestion des formulaires".

Exercice 01 : Introduire v-model sur un champ texte

Objectif : Lier un champ texte à une donnée réactive et afficher sa valeur mise à jour.

Instructions :

  1. Dans la partie <script>, importer la fonction ref depuis Vue.
  2. Déclarer une constante réactive nommée titre initialisée à une chaîne vide via ref().
  3. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 01".
  4. Ajouter un champ texte et lui définir un placeholder explicite (ex. : "Titre de la demande").
  5. Lier le champ texte à la constante titre avec la directive v-model.
  6. Ajouter un paragraphe d'aperçu qui affiche : "Titre : " suivi du contenu de la constante titre.
  7. Tester : saisir du texte dans le champ doit mettre à jour titre via v-model. Comme titre est une constante réactive créée avec ref(), son affichage dans le <template> se met à jour automatiquement.

Exercice 02 : Basculer un statut avec une case à cocher

Objectif : Utiliser une <input type="checkbox"> liée avec v-model pour piloter une donnée booléenne.

Instructions :

  1. Dans la partie <script>, importer ref depuis Vue.
  2. Créer une constante réactive nommée actif initialisée à false via ref().
  3. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 02".
  4. Créer un <fieldset> avec le titre "Visibilité du produit" placé dans une balise <legend>.
  5. Sous la balise <legend>, créer une balise <label>.
  6. Dans la balise <label>, créer une case à cocher (checkbox) et la lier à la constante réactive actif avec la directive v-model.
  7. Ajouter le texte "Rendre le produit visible en ligne" sous la case à cocher (au sein de la balise <label>).
  8. Ajouter un paragraphe d'aperçu affichant : "Statut : " suivi d'un ternaire dans les moustaches basé sur la valeur de la constante actif (ex. : "actif" / "inactif").
  9. Tester : cocher/décocher la case met à jour immédiatement la constante réactive actif qui met automatiquement le texte "Statut : ..." à jour.

Exercice 03 : Sélectionner plusieurs options avec des cases à cocher

Objectif : Alimenter un tableau réactif avec un groupe de cases à cocher (ex. : permissions d'un compte).

Instructions :

  1. Dans la partie <script>, importer ref depuis Vue.
  2. Créer une constante réactive nommée permissions initialisée à un tableau vide via ref().
  3. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 03".
  4. Créer un <fieldset> avec le titre "Permissions" placé dans une balise <legend>.
  5. Sous la balise <legend>, créer une première balise <label>.
  6. Dans cette balise <label>, créer une case à cocher (checkbox) et la lier à la constante réactive permissions avec la directive v-model. Donner à cette case la valeur "lecture" à l'aide de l'attribut HTML value et ajouter le texte "Lecture" au <label>.
  7. Créer une deuxième balise <label> basée sur le même modèle précédent mais cette fois-ci avec la valeur "lecture" et le texte "Écriture".
  8. Créer une troisième balise <label> basée sur le même modèle précédent mais cette fois-ci avec la valeur "admin" et le texte "Administration".
  9. Ajouter un paragraphe d'aperçu affichant "Nombre sélectionné : " suivi du nombre d'élément présent dans le tableau permissions.
  10. Ajouter un paragraphe affichant "Permissions : " puis, successivement, les trois premières cases du tableau.
  11. Tester : cocher/décocher chaque case doit ajouter/retirer sa valeur dans le tableau permissions et mettre à jour l'aperçu immédiatement. (Ne pas utiliser .prevent dans ce cas.)

Exercice 04 : Choisir le statut d'un ticket avec une liste déroulante

Objectif : Lier un <select> à une propriété d'un objet réactif pour mettre à jour le statut d'un ticket.

Instructions :

  1. Dans la partie <script>, importer la fonction reactive depuis Vue.
  2. Créer une constante réactive nommée ticket avec reactive(), contenant les propriétés suivantes :
    • titre : "Problème d'accès".
    • statut : "brouillon".
  3. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 04".
  4. Ajouter un libellé (<label>) pour la liste déroulante. Lui ajouter le texte "Statut" et le lier (avec l'attribut HTML for) à l'identifiant nommé "statut" de la future liste déroulante.
  5. Sous le libellé, créer la liste déroulante <select> avec l'attribut HTML id dont la valeur vaut "statut" et lier la liste à la propriété statut de l'objet réactif ticket à l'aide de la directive v-model.
  6. Créer une première balise option dans la balise select. Donner à cette option la valeur "brouillon" à l'aide de l'attribut HTML value et lui ajouter le texte "Brouillon".
  7. Créer une deuxième balise option dans la balise select. Donner à cette option la valeur "publie" à l'aide de l'attribut HTML value et lui ajouter le texte "Publié".
  8. Créer une première balise option dans la balise select. Donner à cette option la valeur "archive" à l'aide de l'attribut HTML value et lui ajouter le texte "Archivé".
  9. Sous la liste déroulante, ajouter un paragraphe d'aperçu affichant : "Ticket : " suivi de la propriété titre de l'objet ticket.
  10. Créer un seconde paragraphe affichant "Statut : "suivi de la propriété statut de l'objet ticket.
  11. Tester : changer la sélection dans la liste doit mettre à jour immédiatement la propriété ticket.statut et l'aperçu.

Exercice 05 : Découvrir les modificateurs de la directive v-model en additionnant des valeurs numériques saisies par l'utilisateur

Objectif : Lier deux champs numériques à des données réactives pour calculer un total d'heures. Constater le problème sans .number (concaténation) puis corriger avec le modificateur.

Instructions :

  1. Dans la partie <script>, importer ref depuis Vue.
  2. Déclarer deux constantes réactives :
    • heures initialisée à 0 via ref() (heures standard) ;
    • heuresSup initialisée à 0 via ref() (heures supplémentaires).
  3. Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 5".
  4. Dans la section <template>, créer un <fieldset> avec le titre "Temps de travail" placé dans une balise <legend>.
  5. Créer une première paire libellé/champ permettant à l'utilisateur de saisir le nombre d'heures planifiées sur la période :
    • libeller le champ (ex. : "Heures standard") en le liant avec for/id ;
    • utiliser un champ de type text ;
    • lier le champ à la donnée avec v-model sur heures (sans modificateur) ;
  6. Créer une deuxième paire libellé/champ permettant à l'utilisateur de saisir le nombre d'heures supplémentaires effectuées :
    • libeller le champ (ex. : "Heures supplémentaires") ;
    • utiliser un champ de type text ;
    • lier le champ à la donnée avec v-model sur heuresSup (sans modificateur) ;
  7. Sous les champs, ajouter un paragraphe d'aperçu affichant : "Total heures : " suivi d'une expression dans les moustaches qui additionne heures et heuresSup.
  8. Tester (toujours sans .number) : entrer 2 en heures standard et 5 en heures supplémentaires. Constater que le total peut s'afficher comme "25" au lieu de "7".
    Pourquoi ? Sans le modificateur, les champs renvoient des chaînes, et l'opérateur + concatène des chaînes.
  9. Corriger les liaisons pour convertir automatiquement les saisies en nombres en appliquant le modificateur number sur la directive v-model des champs Heures standard et Heures supplémentaires.
  10. Re-tester : avec 2 et 5, le total doit maintenant afficher "7".