III. On se répète…▲
On a vu qu'on pouvait établir une liaison entre une propriété dans le modèle et un élément dans la vue. Mais pour le moment on a utilisé des valeurs simples : nombre ou chaîne de caractères. Dans de multiples cas on aura besoin d'afficher des valeurs contenues dans un tableau ou un objet. Comment procéder dans ce cas ? Vue.js nous propose une directive puissante et simple à utiliser pour réaliser cela.
III-A. La directive v-for▲
La directive v-for permet de répéter l'affichage d'un élément du DOM en fonction des valeurs contenues dans un tableau du modèle. Un petit exemple vous fera comprendre cela rapidement.
Voilà le HTML :
Le but est de créer une liste non ordonnée. On englobe donc avec une balise ul. On prévoit la directive v-for dans la balise li qui doit être répétée, et on précise le nom de la propriété qui contient les objets. On utilise enfin mustache pour les valeurs des items.
Voilà le JavaScript :
2.
3.
4.
5.
6.
7.
8.
9.
10.
new Vue
({
el
:
'#tuto'
,
data
:
{
items
:
[
"Je suis l'item 1"
,
"Je suis l'item 2"
,
"Je suis l'item 3"
]
}
}
);
On a la propriété items qui contient un tableau de valeurs.
Avec ce rendu :
Le tableau est donc parcouru, et pour chaque objet rencontré, une balise li est créée avec la valeur de l'item.
On peut également utiliser for à la place de in pour se rapprocher de la syntaxe des itérateurs.
Voici une illustration du fonctionnement :
III-B. Un index▲
Il est souvent utile de connaître l'index de l'élément répété, et pour l'obtenir il faut ajouter la variable index. Voici un exemple :
Avec ce JavaScript :
2.
3.
4.
5.
6.
7.
8.
9.
10.
new Vue
({
el
:
'#tuto'
,
data
:
{
fruits
:
[
'pomme'
,
'cerise'
,
'abricot'
]
}
}
);
Et ce résultat :
Le principal intérêt de connaître l'index est dans une perspective dynamique. Voici le code HTML modifié pour illustrer cela :
<
li v-for
=
"
(value, index) in fruits
"
@click
=
"
getFruit(index)
"
>
{{
index }}
=> {{
value }}
<
/li
>
On a maintenant en place la détection d'un clic. On transmet comme paramètre l'index.
Voici le JavaScript :
On a une méthode getFruit qui attend l'argument index. Selon la valeur de l'index on va extraire le bon fruit du tableau et obtenir ce genre de message :
Sans cet index on ne pourrait pas localiser l'action.
Voici une illustration de ce fonctionnement :
III-C. Itérer un tableau d'objets▲
On a vu qu'on peut créer une répétition dans le DOM avec un tableau de valeurs. Peut-on aussi le faire à partir d'un tableau d'objets ? La réponse est positive et nous allons voir comment faire avec un premier exemple.
Voici la partie HTML :
La structure est en place et on va répéter des cellules avec les informations du modèle. On se réfère à la propriété personnes du modèle et aux propriétés nom et prenom.
Voici le JavaScript :
2.
3.
4.
5.
6.
7.
8.
9.
10.
new Vue
({
el
:
'#tuto'
,
data
:
{
personnes
:
[
{
nom
:
"Durand"
,
prenom
:
"Jacques"
},
{
nom
:
"Dupont"
,
prenom
:
"Albert"
},
{
nom
:
"Martin"
,
prenom
:
"Denis"
},
]
}
}
);
On a le modèle avec toutes les personnes mémorisées (nom et prénom).
Voici le résultat à l'affichage :
Voici une schématisation du fonctionnement :
III-D. Et si le tableau est modifié ?▲
On a vu que lorsqu'on lie une propriété avec une valeur simple le changement de celle-ci est répercuté dans la vue. Qu'en est-il avec les tableaux ?
III-D-1. Les mutateurs▲
Toutes les méthodes qui modifient un tableau (les mutateurs) sont prises en compte. Voici les mutateurs en œuvre.
On conserve le HTML utilisé ci-dessus :
Avec ce JavaScript :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
var vm =
new Vue
({
el
:
'#tuto'
,
data
:
{
personnes
:
[
{
nom
:
"Durand"
,
prenom
:
"Jacques"
},
{
nom
:
"Dupont"
,
prenom
:
"Albert"
},
{
nom
:
"Martin"
,
prenom
:
"Denis"
},
]
}
}
);
setTimeout
(
function(
){
vm.
personnes.push
({
nom
:
"Claret"
,
prenom
:
"Marcel"
}
);},
2000
);
setTimeout
(
function(
){
vm.
personnes.pop
(
);},
4000
);
setTimeout
(
function(
){
vm.
personnes.unshift
({
nom
:
"Claret"
,
prenom
:
"Marcel"
}
);},
6000
);
setTimeout
(
function(
){
vm.
personnes.shift
(
);},
8000
);
setTimeout
(
function(
){
vm.
personnes.splice
(
1
,
1
,
{
nom
:
"Claret"
,
prenom
:
"Marcel"
}
);},
10000
);
setTimeout
(
function(
){
vm.
personnes.sort
(
function (
a,
b) {
return (
a.
nom >
b.
nom) }
);},
12000
);
setTimeout
(
function(
){
vm.
personnes.reverse
(
);},
14000
);
Lorsque vous chargez la page, le tableau apparaît comme présenté ci-dessus, puis toutes les deux secondes il se transforme conformément aux méthodes utilisées. Vous allez constater que le tableau de la vue suit fidèlement les changements du tableau du modèle.
III-D-2. Les accesseurs▲
Les accesseurs ne modifient pas un tableau mais en retournent un nouveau. Dans ce cas évidemment les modifications ne sont pas répercutées. Il faut donc remplacer l'ancien tableau par le nouveau. Prenons un nouvel exemple, le HTML est le même que ci-dessus :
Voici la partie JavaScript :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
var vm =
new Vue
({
el
:
'#tuto'
,
data
:
{
personnes
:
[
{
nom
:
"Durand"
,
prenom
:
"Jacques"
},
{
nom
:
"Dupont"
,
prenom
:
"Albert"
},
{
nom
:
"Martin"
,
prenom
:
"Denis"
},
]
}
}
);
setTimeout
(
function(
){
vm.
personnes =
vm.
personnes.concat
([
{
nom
:
"Claret"
,
prenom
:
"Marcel"
},
{
nom
:
"Verlou"
,
prenom
:
"Gustave"
}
]
);
},
2000
);
setTimeout
(
function(
){
vm.
personnes =
vm.
personnes.slice
(
1
,
4
);},
4000
);
On a encore une modification du tableau toutes les deux secondes. Vous remarquerez que cette fois il a fallu affecter à nouveau le tableau pour prendre en compte les modifications.
III-D-3. Modification d'un élément de tableau▲
Regardez maintenant cet exemple :
Dans ce cas le tableau ne sera pas mis à jour dans la vue.
Pour y parvenir, Vue.js propose la méthode set :
Cette fois le nouvel objet sera pris en compte !
III-E. Itérer un objet▲
Maintenant voyons le cas de l'itération d'un objet avec un exemple simple.
Voici le HTML :
Et le JavaScript :
2.
3.
4.
5.
6.
7.
8.
9.
new Vue
({
el
:
'#tuto'
,
data
:
{
personne
:
{
nom
:
"Durand"
,
prenom
:
"Jacques"
}
}
}
);
On va ainsi itérer les propriétés de l'objet personne :
Il est aussi possible de récupérer les clés. Voici l'exemple ci-dessus complété :
Le JavaScript est le même et voici le résultat :
III-F. Un exemple▲
Avec tout ce que nous avons vu jusqu'à présent, nous allons pouvoir élaborer un exemple un peu plus intéressant. Disons que nous avons une liste de personnes dans un tableau. Nous voulons pour chaque personne un bouton pour la mettre à la poubelle. On a donc aussi une liste de personnes en poubelle. Dans cette poubelle nous voulons pouvoir soit rétablir la personne dans la liste des personnes, soit la supprimer complètement. Vous comprendrez sans doute mieux en faisant fonctionner l'exemple.
Voici le code complet :
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.
<!
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.7/css/bootstrap.min.css
"
>
<
/head
>
<
body>
<
div class
=
"
container
"
id
=
"
tuto
"
>
<
br>
<
div class
=
"
panel panel-primary
"
v-show
=
"
personnes.length
"
>
<
div class
=
"
panel-heading
"
>
Personnes actives<
/div
>
<
table class
=
"
table table-bordered table-striped
"
>
<
thead>
<
tr>
<
th class
=
"
col-sm-5
"
>
Nom<
/th
>
<
th class
=
"
col-sm-5
"
>
Prénom<
/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-warning btn-block
"
@click
=
"
supprimer(index)
"
>
Poubelle<
/button
></td
>
<
/tr
>
<
/tbody
>
<
/table
>
<
div class
=
"
panel-footer
"
>
 
<
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
"
@click
=
"
retablir(index)
"
>
Rétablir<
/button
></td
>
<
td><button class
=
"
btn btn-danger btn-block
"
@click
=
"
eliminer(index)
"
>
Supprimer<
/button
></td
>
<
/tr
>
<
/tbody
>
<
/table
>
<
div class
=
"
panel-footer
"
>
 
<
div class
=
"
btn-group
"
>
<
button class
=
"
button btn btn-xs btn-success
"
@click
=
"
toutRetablir
"
>
Tout rétablir<
/button
>
<
button class
=
"
button btn btn-xs btn-danger
"
@click
=
"
toutEliminer
"
>
Tout supprimer<
/button
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<script src
=
"
https://unpkg.com/vue@2.0.3/dist/vue.js
"
></
script>
<script>
var
vm =
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
:
[]
},
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 =
[];
}
}
}
);
var
ordonner =
function
(
a,
b) {
return
(
a.
nom >
b.
nom) };
</
script>
<
/body
>
<
/html
>
Au départ on a la liste des personnes :
Pour chaque personne on dispose d'un bouton pour la mettre à la poubelle. On a aussi un bouton pour mettre tout le monde à la poubelle. Si je clique, par exemple, sur le bouton de Dupont, j'obtiens :
Le panneau de la poubelle devient visible avec Dupont présent. On dispose d'un bouton pour le rétablir et d'un autre pour le supprimer définitivement. Si on clique sur « Rétablir » on se retrouve dans la situation initiale.
Si on envoie Martin aussi à la poubelle, on se retrouve ainsi :
On remarque que la liste de la poubelle s'ordonne automatiquement.
Si on envoie tout le monde à la poubelle, le premier panneau disparaît et il ne reste que la liste de la poubelle :
On peut rétablir une ou toutes les personnes d'un coup. Vous avez compris le principe, je vous laisse faire des tests et analyser le code, il ne comporte que des choses que nous avons déjà vues, et c'est une bonne occasion pour réviser ce qui a été présenté lors des articles précédents.
III-G. En résumé▲
- La directive v-for permet de répéter des éléments du DOM à partir de données du modèle.
- La directive v-for génère un index pour identifier les éléments.
- On peut itérer un tableau de valeurs ou d'objets.
- Lorsqu'on utilise un accesseur il faut assigner de nouveau le tableau généré.
- On dispose de la méthode set pour modifier un élément de tableau.