Tutoriel VueJS 3 – Formulaires et v-model

Dans cette leçon, nous allons étudier le concept de liaison d’attributs.

Notre objectif

Créez un formulaire permettant aux utilisateurs d’ajouter des avis sur les produits, avant de commencer, vous devez ajouter ce code css à votre feuille de style.

assets/styles.css
...

.review-form {
  display: flex;
  flex-direction: column;
  width: 425px;
  padding: 20px;
  margin: 40px;
  border: 2px solid #d8d8d8;
  background-color: white;
  -webkit-box-shadow: 0px 2px 15px -12px rgba(0, 0, 0, 0.57);
  -moz-box-shadow: 0px 2px 15px -12px rgba(0, 0, 0, 0.57);
  box-shadow: 2px 15px -12px rgba(0, 0, 0, 0.57);
}

.review-container {
  width: 425px;
  padding: 20px;
  background-color: white;
  -webkit-box-shadow: 0px 2px 20px -12px rgba(0, 0, 0, 0.57);
  -moz-box-shadow: 0px 2px 20px -12px rgba(0, 0, 0, 0.57);
  box-shadow: 2px 20px -12px rgba(0, 0, 0, 0.57);
  margin-left: 40px;
  border: 2px solid #d8d8d8;
}

.review-container li {
  margin-bottom: 30px;
}

.review-form .button {
  display: block;
  margin: 30px auto;
}

@media only screen and (max-width: 600px) {
  .container {
    flex-direction: column;
  }

  .product-image,
  .product-info {
    margin-left: 10px;
    width: 100%;
  }

  .review-form {
    width: 90%;
  }
}

Présentation du v-model

Au début de ce cours, nous avons appris l’existence de v-bind, qui crée une liaison à sens unique, des données au modèle. Cependant, lorsque nous travaillons avec des formulaires, cette liaison unidirectionnelle n’est pas suffisante. Nous devons également lier le modèle aux données.

Par exemple, lorsqu’un utilisateur saisit son nom dans un champ de saisie, nous voulons enregistrer et stocker cette valeur dans nos données. La directive v-model nous aide à y parvenir, en créant une liaison de données bidirectionnelle.

Pour voir tout cela en action, nous allons créer un nouveau composant de review-form

La composante review-form

Nous allons ajouter un nouveau fichier ReviewForm.js dans notre dossier de composants, et échafauder le composant.

ReviewForm.js
app.component('review-form', {
  template:
  `<form class="review-form">
    <h3>Laissez un commentaire</h3>
    <label for="name">Nom:</label>
    <input id="name">

    <label for="review">Avis:</label>      
    <textarea id="review"></textarea>

    <label for="rating">Note:</label>
    <select id="rating">
      <option>5</option>
      <option>4</option>
      <option>3</option>
      <option>2</option>
      <option>1</option>
    </select>

    <input class="button" type="submit" value="Envoyer">
  </form>`,
  data() {
    return {
      name: '',
      review: '',
      rating: null
    }
  }
})

À l’intérieur de notre modèle, remarquez ces éléments :

Nous voulons lier ces champs de saisie à leurs propriétés de données respectives afin que, lorsque l’utilisateur remplit le formulaire, nous stockions ses données localement.

data() {
    return {
      name: '',
      review: '',
      rating: null
    }
}

Pour ce faire, nous allons ajouter la directive v-model à chacun de ces éléments d’entrée.

components/ReviewForm.js
app.component('review-form', {
  template:
  `<form class="review-form">
    <h3>Laissez un commentaire</h3>
    <label for="name">Nom:</label>
    <input id="name" v-model="name">

    <label for="review">Avis:</label>      
    <textarea id="review" v-model="review"></textarea>

    <label for="rating">Note:</label>
    <select id="rating" v-model.number="rating">
      <option>5</option>
      <option>4</option>
      <option>3</option>
      <option>2</option>
      <option>1</option>
    </select>

    <input class="button" type="submit" value="Envoyer">  
  </form>`,
  data() {
    return {
      name: '',
      review: '',
      rating: null
    }
  }
})

Remarquez comment sur l’élément <select>, nous avons utilisé v-model.number, c’est un modificateur qui typographie la valeur comme un nombre.

Soumettre le formulaire de révision

Afin de soumettre ce formulaire, nous allons ajouter un écouteur en haut :

components/ReviewForm.js
app.component('review-form', {
  template:
  `<form class="review-form" @submit.prevent="onSubmit">
    ...
    <input class="button" type="submit" value="Envoyer">  
  </form>`
  ...
})

Nous utilisons un autre modificateur, @submit.prevent="onSubmit" pour empêcher le comportement par défaut (un rafraîchissement du navigateur). Lorsque ce formulaire est soumis, il déclenche la méthode onSubmit(), que nous allons écrire maintenant :

components/ReviewForm.js
...
data() {
  return {
    name: '',
    review: '',
    rating: null
   }
 },
 methods: {
   onSubmit() {
     let productReview = {
       name: this.name,
       review: this.review,
       rating: this.rating,
     }
     this.$emit('review-submitted', productReview)

     this.name = ''
     this.review = ''
     this.rating = null
   }
 }
...

Cette méthode créera un objet productReview, contenant le nom, l’avis et l’évaluation de nos données. Elle émettra ($emit) ensuite un événement, review-submitted, en envoyant cet objet productReview au payload.

Enfin, nous effaçons les champs de données.

Utilisation du formulaire de révision

Maintenant que notre formulaire d’évaluation est créé, nous pouvons l’importer dans index.html.

index.html
<!-- Importer le composant -->
...
<script src="./components/ReviewForm.js"></script>
...

Puis nous nous dirigerons vers product-display, et utiliserons réellement le composant dans son modèle, sous le « product-container« .

components/ProductDisplay.js
template: 
  `<div class="product-display">
    <div class="product-container">
     ...
    </div>
    <review-form></review-form>
  </div>`
})

Maintenant, dans le navigateur, nous pouvons voir le formulaire de révision.

Tout semble fonctionner… sauf que lorsque nous cliquons sur le bouton d’envoi, nous émettons l’événement, mais nous ne l’avons écouté nulle part. Comme nous l’avons appris dans la leçon précédente, nous devons écouter l’événement review-submitted dans la portée parent (dans product-display).

Lorsque l’événement est « entendu », nous ajoutons les données productReview aux données du composant product-display.

Ajout de commentaires sur les produits

Nous allons ajouter l’écouteur d’événements ici, sur le review-form, là où il est utilisé :

components/ProductDisplay.js
template: 
  /*html*/
  `<div class="product-display">
    <div class="product-container">
     ...
    </div>
    <review-form @review-submitted="addReview"></review-form>
  </div>`
})

Lorsque l’événement se produit, nous allons déclencher une nouvelle méthode addReview(). Cela ajoutera les avis sur les produits à notre composant product-display, ce qui signifie que ce composant a besoin d’un nouveau tableau d’avis dans ses données.

components/ProductDisplay.js
...
data() {
  return {
    ...
    reviews: []
  }
}
...

Maintenant, nous allons étoffer la méthode addReview() :

components/ProductDisplay.js
...
data() {
  return {
    ...
    reviews: []
   }
 },
methods: {
  ...
  addReview(review) {
    this.reviews.push(review)
  }
},
...

Comme vous pouvez le voir, il prend le review que nous avons obtenu à partir du payload de l’événement review-submitted, et le pousse dans le tableau reviews.

Affichage des reviews

Maintenant que nous avons implémenté la possibilité d’ajouter des avis, nous devons afficher ces avis. Créons un nouveau composant à cet effet. Ce composant s’appellera review-list, que nous allons structurer comme ceci :

components/ReviewList.js
app.component('review-list', {
  props: {
    reviews: {
      type: Array,
      required: true
    }
  },
  template:
  `
  <div class="review-container">
  <h3>Avis:</h3>
    <ul>
      <li v-for="(review, index) in reviews" :key="index">
        {{ review.name }} a donné {{ review.rating }} étoiles
        <br/>
        "{{ review.review }}"
        <br/>
      </li>
    </ul>
  </div>
`
})

Il aura un prop pour recevoir les avis et les imprimer dans le modèle en utilisant v-for, y compris l’index, afin que nous puissions lui lier l’attribut :key.

Nous pouvons maintenant importer ce composant dans index.html :

index.html
<!-- Importer le composant -->
...
<script src="./components/ReviewList.js"></script>
...

Ajoutez-le ensuite dans le display-product, juste au-dessus de notre review-form :

components/ProductDisplay.js
template: 
  `<div class="product-display">
    <div class="product-container">
     ...
    </div>
    <review-list :reviews="reviews"></review-list>
    <review-form @review-submitted="addReview"></review-form>
  </div>`
})
Remarquez que nous avons ajouté :reviews="reviews" afin de transmettre les reviews qui se trouvent sur product-display dans la liste des reviews. En vérifiant dans le navigateur, nous ajouterons un nouvel avis, cliquerons sur « submit » et verrons que l’avis est affiché.

Jusqu’ici tout va bien, mais lorsque nous rafraîchissons la page (et qu’il n’y a pas d’avis), nous voyons toujours une boîte vide parce que le composant de la review-list est toujours rendu sans avis à imprimer. Corrigeons cela, et ne rendons ce composant que lorsque nous avons des reviews à afficher.

components/ProductDisplay.js
template: 
  `<div class="product-display">
    ...
    <review-list v-if="reviews.length" :reviews="reviews"></review-list>
    ...
  </div>`
})

En d’autres termes, si le tableau des reviews est vide, nous n’afficherons pas le composant de la review-list.

Avec un rafraîchissement, il semble que cela fonctionne, et le composant ne s’affiche qu’après l’ajout d’une critique.

Validation de base des formulaires

Pour terminer cette leçon, nous allons ajouter une validation très basique à notre review-form.

components/ReviewForm.js
methods: {
  onSubmit() {
    if (this.name === '' || this.review === '' || this.rating === null) {
      alert('L\'évaluation est incomplète. Veuillez remplir tous les champs.')
      return
    }
  ...
  }
}

Avant de créer un productReview, nous allons vérifier si this.name ou this.review ou this.rating sont vides. Si l’une de ces choses est le cas, nous allons afficher une alert, qui dit : "L'évaluation est incomplète. Veuillez remplir tous les champs". Puis, nous sortons de la méthode.

Il s’agit d’une méthode simple de validation des formulaires.

Félicitations !

Vous êtes arrivé à la fin de ce tutoriel et avez les bases pour commencer à coder avec VueJS 3. Pour continuer à apprendre, je vous invite à consulter mes articles sur VueJS.

Ressources

Pensez à télécharger le code de départ pour commencer cette étape du tutoriel dans de bonnes conditions.

Newsletter

Ne manquez jamais les nouveaux conseils, tutoriels et autres.

Pas de spam, jamais. Nous ne partagerons jamais votre adresse électronique et vous pouvez vous désabonner à tout moment.