Tutoriel pour apprendre à utiliser le framework Vue.js version 2

Les bases


précédentsommairesuivant

IV. Double liaison

Contrairement à ce que le titre de ce chapitre pourrait suggérer, il ne s'agit pas de mœurs dissolues mais toujours de notre bibliothèque JavaScript. On a vu au cours des chapitres précédents qu'on peut facilement établir un lien entre le modèle et la vue et que, si le modèle change, alors la vue change aussi pour refléter ce changement.

Maintenant nous allons nous intéresser à l'inverse, autrement dit : si on change quelque chose dans la vue, est-ce que ça va modifier le modèle ? Comme Vue.js est censé justement établir une double liaison, ça devrait pouvoir se faire.

IV-A. La directive v-model

La directive v-model crée une double liaison entre le modèle et un contrôle de formulaire : input, select, checkbox, textarea… Donc tout changement dans le modèle est répercuté dans le contrôle et réciproquement. Prenons un petit exemple simple, voici le HTML :

 
Sélectionnez
<form id="tuto">
  <input type="text" v-model="texte"><p>{{ texte }}</p>
</form>

Et le JavaScript :

 
Sélectionnez
1.
2.
3.
4.
new Vue({
  el: '#tuto',
  data: { texte: 'coucou' }
});

Le résultat est un contrôle de texte et un texte associé au-dessous. Lorsqu'on change le texte dans le contrôle, le texte associé change également :

Image non disponible

Voici une illustration du fonctionnement :

Image non disponible

Pour être sûr que ça marche dans les deux sens vous pouvez ajouter cette ligne à la fin du JavaScript :

 
Sélectionnez
setTimeout(function(){ vm.texte = 'Nouveau texte'; }, 2000);

Et vous verrez que deux secondes après le chargement de la page, le nouveau texte figurera aux deux emplacements. C'est bien de la double liaison !

IV-B. Boutons radio et cases à cocher

Les boutons radio et les cases à cocher ont ceci de particulier qu'ils fonctionnent en « tout ou rien ».

IV-B-1. Boutons radio

Les boutons radio s'utilisent groupés puisqu'un seul peut être coché.

Voici un exemple de mise en œuvre HTML :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
<form id="tuto">
  <div class="radio">
    <label>
      <input type="radio" name="sexe" value="male" v-model="sexe"> Male
    </label>
  </div>
  <div class="radio">
    <label>
      <input type="radio" name="sexe" value="femelle" v-model="sexe"> Femelle
    </label>
  </div>
  <div class="form-control">
    On a choisi {{ sexe }}
  </div>
</form>

Et le JavaScript :

 
Sélectionnez
1.
2.
3.
4.
new Vue({
  el: '#tuto',
  data: { sexe: 'male' }
});

On a donc besoin d'une seule propriété qui a pour valeur celle du bouton radio coché. Au départ on a ceci :

Image non disponible

Et quand on coche l'autre bouton, on a :

Image non disponible

Voici une illustration du fonctionnement :

Image non disponible

La valeur d'une case à cocher est en général une chaîne de caractères statique. Il peut arriver qu'on ait besoin d'un comportement dynamique. Il suffit alors d'établir une liaison avec la directive v-bind :

 
Sélectionnez
<input type="radio" name="sexe" v-bind:value="male" v-model="sexe"> Male

IV-B-2. Cases à cocher

Les cases à cocher peuvent être solitaires, contrairement aux boutons radio. Prenons un exemple…

Voici le HTML :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
<form id="tuto">
  <div class="checkbox">
    <label>
      <input type="checkbox" name="nom" value="valeur" v-model="checked"> Je suis <strong>{{ checked }}</strong>
    </label>
  </div>
</form>

Et le JavaScript :

 
Sélectionnez
1.
2.
3.
4.
new Vue({
  el: '#tuto',
  data: { checked: false }
});

Au départ on a ceci :

Image non disponible

On aurait évidemment la case cochée si on avait affecté true à checked.

Lorsqu'on clique on obtient l'état inverse :

Image non disponible

La valeur d'une case à cocher est en général un booléen qui peut être vrai ou faux. Il peut arriver qu'on ait besoin d'autres types de données. Il suffit alors d'établir une liaison avec la directive v-bind :

 
Sélectionnez
1.
2.
3.
4.
5.
<input type="checkbox" 
    name="nom" 
    v-bind:true-value="vrai"
    v-bind:false-value="faux"
    v-model="checked">

IV-C. Liste de choix

Une liste de choix propose une liste d'éléments, le plus souvent sous forme déroulante. C'est un contrôle très utilisé.

IV-C-1. Sélection simple

Commençons avec un exemple simple, voici le HTML :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
<form id="tuto">
  <select class="form-control" v-model="choix">
    <option>Choix 1</option>
    <option>Choix 2</option>
    <option>Choix 3</option>
  </select>
  <p>On a choisi "{{ choix }}"</p>
</form>

Et le JavaScript :

 
Sélectionnez
1.
2.
3.
4.
new Vue({
  el: '#tuto',
  data: { choix: 'Choix 2' }
});

Au départ on a cette situation :

Image non disponible

Et selon ce qu'on sélectionne, le texte suit fidèlement :

Image non disponible

IV-C-2. Sélections multiples

On peut désirer pouvoir choisir plusieurs éléments dans une liste de choix en utilisant l'attribut multiple. Voici notre exemple modifié en conséquence :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
<form id="tuto">
  <select class="form-control" v-model="choix" multiple>
    <option>Choix 1</option>
    <option>Choix 2</option>
    <option>Choix 3</option>
  </select>
  <p>On a choisi "{{ choix }}"</p>
</form>

Et le JavaScript :

 
Sélectionnez
1.
2.
3.
4.
new Vue({
  el: '#tuto',
  data: { choix: ['Choix 2', 'Choix 3'] }
});

Comme on a plusieurs choix possibles on utilise un tableau de valeurs. Au départ on a :

Image non disponible

Et selon les choix suivants, l'affichage s'adapte :

Image non disponible

IV-C-3. Options dynamiques

On a souvent besoin de remplir de façon dynamique une liste de choix, et pour le faire on met à contribution la directive v-for qu'on connaît déjà. Mais il faut également gérer la liaison entre les options et leurs valeurs dans le modèle, on le fait avec une directive v-bind (ici j'ai utilisé la syntaxe courte avec les deux points) :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
<form id="tuto">
  <select class="form-control" v-model="choix" multiple>
    <option v-for="option in options" :value="option.value">
      {{ option.text }}
    </option>
  </select>
  <p>On a choisi "{{ choix }}"</p>
</form>

Et le JavaScript :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
var vm = new Vue({
  el: '#tuto',
  data: { 
    choix: [1, 3],
    options: [
      { text: 'Choix 1', value: '1' },
      { text: 'Choix 2', value: '2' },
      { text: 'Choix 3', value: '3' }
    ],
  }
});

setTimeout(function(){ Vue.set(vm.options, 1, { text: 'Choix 2a', value: '2a' })}, 2000);

Au bout de deux secondes on change la deuxième option de la liste.

IV-D. Un exemple

Nous allons poursuivre l'exemple du précédent chapitre en ajoutant la possibilité de modifier les données d'une personne et aussi d'en ajouter une. Voici le code complet :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
<!DOCTYPE html>
<html lang="fr">

  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Test vue.js</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
  </head>

  <body>

    <div class="container" id="tuto">
      <br>

      <div class="panel panel-primary">
        <div class="panel-heading">Personnes actives</div>        
        <table class="table table-bordered table-striped">
          <thead>
            <tr>
             <th class="col-sm-4">Nom</th>
             <th class="col-sm-4">Prénom</th>
             <th class="col-sm-2"></th>
             <th class="col-sm-2"></th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(personne, index) in personnes">
              <td>{{ personne.nom }}</td>
              <td>{{ personne.prenom }}</td> 
              <td><button class="btn btn-info btn-block" @click="modifier(index)">Modifier</button></td>
              <td><button class="btn btn-warning btn-block" @click="supprimer(index)">Poubelle</button></td>
            </tr>  
            <tr>
              <td><input type="text" class="form-control" v-model="inputNom" ref="modif" placeholder="Nom"></td>
              <td><input type="text" class="form-control" v-model="inputPrenom" placeholder="Prénom"></td>
              <td colspan="2"><button class="btn btn-primary btn-block" @click="ajouter()">Ajouter</button></td>
            </tr>
          </tbody>       
        </table>
        <div class="panel-footer">
          &nbsp
          <button class="button btn btn-xs btn-warning" @click="toutPoubelle">Tout à la poubelle</button>
        </div>
      </div> 

      <div class="panel panel-danger" v-show="poubelle.length">
        <div class="panel-heading">Poubelle</div>
        <table class="table table-bordered table-striped">
          <thead>
            <tr>
             <th class="col-sm-4">Nom</th>
             <th class="col-sm-4">Prénom</th>
             <th class="col-sm-2"></th>
             <th class="col-sm-2"></th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(personne, index) in poubelle">
              <td>{{ personne.nom }}</td>
              <td>{{ personne.prenom }}</td> 
              <td><button class="btn btn-success btn-block" v-on:click="retablir(index)">Rétablir</button></td>
              <td><button class="btn btn-danger btn-block" v-on:click="eliminer(index)">Supprimer</button></td>    
            </tr>  
          </tbody>       
        </table>
        <div class="panel-footer">
          &nbsp
          <div class="btn-group">
            <button class="button btn btn-xs btn-success" v-on:click="toutRetablir">Tout rétablir</button>
            <button class="button btn btn-xs btn-danger" v-on:click="toutEliminer">Tout supprimer</button> 
          </div>
        </div>
      </div> 

    </div>

    <script src="https://unpkg.com/vue@2.0.3/dist/vue.js"></script>

    <script>

      new Vue({
        el: '#tuto',
        data: {
          personnes: [
            {nom: "Claret", prenom: "Marcel"},
            {nom: "Dupont", prenom: "Albert"},
            {nom: "Durand", prenom: "Jacques"},            
            {nom: "Martin", prenom: "Denis"},
            {nom: "Torlet", prenom: "Arthur"}            
          ],
          poubelle: [],
          inputNom: '',
          inputPrenom: ''
        },
        methods: {
          supprimer: function(index) {
            this.poubelle.push(this.personnes[index]);
            this.personnes.splice(index, 1);
            this.poubelle.sort(ordonner);
          },
          retablir: function(index) {
            this.personnes.push(this.poubelle[index]);
            this.poubelle.splice(index, 1);
            this.personnes.sort(ordonner);
          },
          eliminer: function(index) {
            this.poubelle.splice(index, 1);
          },
          toutPoubelle: function() {
            this.poubelle = this.poubelle.concat(this.personnes);
            this.poubelle.sort(ordonner);
            this.personnes = [];
          },
          toutRetablir: function() {
            this.personnes = this.personnes.concat(this.poubelle);
            this.personnes.sort(ordonner);
            this.poubelle = [];
          },
          toutEliminer: function() {
            this.poubelle = [];
          },
          ajouter: function() {
            this.personnes.push({nom: this.inputNom, prenom: this.inputPrenom});
            this.inputNom = this.inputPrenom = '';
            this.personnes.sort(ordonner);
          },
          modifier: function(index) {
            this.inputNom = this.personnes[index].nom;
            this.inputPrenom = this.personnes[index].prenom;
            this.personnes.splice(index, 1);
            this.$refs.modif.focus();
          }
        }
      });

      var ordonner = function (a, b) { 
        return (a.nom.toUpperCase() > b.nom.toUpperCase())
      };

    </script>

  </body>

</html>

Nous allons nous intéresser à ce qui a été ajouté.

Lorsqu'on lance la page on obtient ceci :

Image non disponible

IV-D-1. Ajouter une personne

On voit la présence d'un formulaire sur la dernière ligne du tableau. Si on insère un nom, il va naturellement prendre sa place dans la liste et le formulaire se remet en situation de départ. Voyons comment cela est réalisé.

Voici le code du formulaire :

 
Sélectionnez
<td><input type="text" class="form-control" v-model="inputNom" ref="modif" placeholder="Nom"></td>
<td><input type="text" class="form-control" v-model="inputPrenom" placeholder="Prénom"></td>
<td colspan="2"><button class="btn btn-primary btn-block" @click="ajouter()">Ajouter</button></td>

Les deux zones de texte sont équipées d'une directive v-model que vous connaissez bien désormais. Le bouton a une directive v-on pour la gestion de l'événement click.

On trouve également un attribut ref. Le but est de pouvoir identifier l'élément du DOM concerné. Cela va nous servir plus loin pour placer le focus.

Pour gérer ces deux contrôles, ont été ajoutées deux propriétés dans le modèle :

 
Sélectionnez
1.
2.
3.
4.
5.
data: {
  ...
  inputNom: '',
  inputPrenom: ''
},

Pour l'ajout de la personne on a prévu la méthode ajouter :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
methods: {
  
    ...
    
  ajouter: function() {
    this.personnes.push({nom: this.inputNom, prenom: this.inputPrenom});
    this.inputNom = this.inputPrenom = '';
    this.personnes.sort(ordonner);
  },

    ...
}
  • on ajoute les données saisies aux personnes ;
  • on réinitialise les contrôles ;
  • enfin on force le classement pour bien placer alphabétiquement la nouvelle personne.

Je ne fais aucun contrôle de saisie pour conserver la simplicité de l'exemple.

IV-D-2. Modifier une personne

On dispose d'un bouton de modification pour chaque personne de la liste :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
<tr v-for="(personne, index) in personnes">
  <td>{{ personne.nom }}</td>
  <td>{{ personne.prenom }}</td> 
  <td><button class="btn btn-info btn-block" @click="modifier(index)">Modifier</button></td>
  <td><button class="btn btn-warning btn-block" @click="supprimer(index)">Poubelle</button></td>
</tr>

Et on a la méthode modifier :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
methods: {
  
  ...

  modifier: function(index) {
    this.inputNom = this.personnes[index].nom;
    this.inputPrenom = this.personnes[index].prenom;
    this.personnes.splice(index, 1);
    this.$refs.modif.focus();
  }
}
  • on place dans les deux zones de texte le nom et le prénom ;
  • on supprime la personne de la liste ;
  • on met l'accent dans la zone de texte du prénom (on voit là l'intérêt d'avoir mis l'attribut ref dans ce contrôle). Remarquez la syntaxe un peu particulière.

Ce qui donne ce genre d'affichage :

Image non disponible

Dupont est en saisie et il a disparu de la liste. On peut modifier nom et prénom. Quand on clique sur « Ajouter », les données modifiées vont prendre leur place dans la liste comme on l'a vu ci-dessus dans le cas de l'ajout d'une personne.

IV-E. En résumé

  • La directive v-model permet d'établir une double liaison.
  • Tous les contrôles de formulaire peuvent utiliser cette directive.
  • Pour remplir de façon dynamique une liste de choix on utilise les directives v-for et v-bind.
  • L'attribut ref permet d'identifier un élément du DOM.

précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2017 Laravel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.