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 :
Et le JavaScript :
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 :
Voici une illustration du fonctionnement :
Pour être sûr que ça marche dans les deux sens vous pouvez ajouter cette ligne à la fin du JavaScript :
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 :
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 :
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 :
Et quand on coche l'autre bouton, on a :
Voici une illustration du fonctionnement :
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 :
IV-B-2. Cases à cocher▲
Les cases à cocher peuvent être solitaires, contrairement aux boutons radio. Prenons un exemple…
Voici le HTML :
Et le JavaScript :
Au départ on a ceci :
On aurait évidemment la case cochée si on avait affecté true à checked.
Lorsqu'on clique on obtient l'état inverse :
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 :
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 :
Et le JavaScript :
2.
3.
4.
new Vue
({
el
:
'#tuto'
,
data
:
{
choix
:
'Choix 2'
}
}
);
Au départ on a cette situation :
Et selon ce qu'on sélectionne, le texte suit fidèlement :
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 :
Et le JavaScript :
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 :
Et selon les choix suivants, l'affichage s'adapte :
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) :
Et le JavaScript :
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 :
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
"
>
 
<
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
"
>
 
<
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 :
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 :
<
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 :
2.
3.
4.
5.
data
:
{
...
inputNom
:
''
,
inputPrenom
:
''
},
Pour l'ajout de la personne on a prévu la méthode ajouter :
- 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 :
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 :
- 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 :
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.