Commentaires
Maintenant que nous avons appris à gérer des données dans Vue, nous allons maintenant commencer à les utiliser en les affichant sur nos pages. Ce principe est appelé le templating.

La première des choses à apprendre est bien évidemment d'afficher une donnée. Pour ça, Vue utilise le style moustache, c'est à dire 2 accolades ouvrantes/fermantes :
{{ maDonnee }}
{"language":"text/html","content":"<!DOCTYPE html>\n<html lang=\"fr\">\n<head>\n\t<meta charset=\"utf-8\">\n\t<title>Mes premiers pas avec Vue 3 : templating</title>\n</head>\n<body>\n\t<main id=\"app\">\n\t\tCatégorie de tutoriels : {{ category }}\n\t</main>\n\t<script src=\"https://unpkg.com/vue@next\"></script>\n\t<script>\n\t\tconst Tutorials = {\n\t\t\tdata() {\n\t\t\t return {\n\t\t\t \tcategory: 'Vue JS',\n\t\t\t }\n\t\t\t}\n\n\t\t}\n\t\tconst app = Vue.createApp(Tutorials).mount('#app')\n\n\t</script>\n</body>\n</html>","filename":"index.html"}


Arthur, l'apprenti développeurTout simplement !
Hé oui, tout simplement.

Contrairement à beaucoup de tutoriels que tu pourrais trouver sur le net, je vais directement parler de l'affichage des listes dans Vue pour te présenter quelque chose de très concret.

Arthur, l'apprenti développeurL'affichage de listes ?
Oui, en fait, si notre donnée est un tableau ou un objet, on peut le parcourir avec une boucle, ça parait logique. On peut également le faire directement dans notre HTML pour générer un affichage commun pour chaque élément du tableau.

L'idée de cette partie va être d'afficher une liste de photos récupérées depuis une API.

{"language":"text/html","content":"<!DOCTYPE html>\n<html lang=\"fr\">\n<head>\n\t<meta charset=\"utf-8\">\n\t<title>Mes premiers pas avec Vue 3 : templating</title>\n</head>\n<body>\n\t<main id=\"app\">\n\t\t<h1>Les photos de l'album : {{ album }}</h1>\n\t\t\n\t</main>\n\t<script src=\"https://unpkg.com/vue@next\"></script>\n\t<script>\n\t\tconst Tutorials = {\n\t\t\tdata() {\n\t\t\t return {\n\t\t\t \talbum: 1,\n\t\t\t \tphotos:[]\n\t\t\t }\n\t\t\t},\n\t\t\tcreated() {\n\t\t\t\tfetch('https://jsonplaceholder.typicode.com/albums/1/photos')\n \t\t\t\t.then((response) => response.json())\n \t\t\t\t.then((json) => {this.photos= json});\n\t\t\t}\n\t\t}\n\t\tconst app = Vue.createApp(Tutorials).mount('#app')\n\t</script>\n</body>\n</html>","filename":"index.html"}

Dans cette partie nous voulons afficher chacune des images de l'album, le code HTML pour chaque photo est donc :

{"language":"text/html","content":"<figure>\n\t<img src=\"URL\" alt=\"TITRE\" />\n\t<figcaption>TITRE</figcaption>\n</figure>","filename":""}

C'est parti !

Les directives avec Vue


Avant d'attaquer l'affichage de listes, nous devons apprendre à utiliser les directives avec Vue.

Arthur, l'apprenti développeurLes quoi ?
Les directives. Ce sont des attributs spéciaux qu'on met dans notre HTML, notre template, qui contiennent une expression Javascript que Vue peut lire, interpréter et exécuter de sorte que le rendu soit réactif quand l'expression change ;)
Autrement dit, si ce que je mets dans ma directive change, l'affichage change de manière réactive !

Il existe plusieurs directives. La première que nous allons voir est la directive conditionnelle : v-if.

v-if, v-else, v-else-if


Cette directive s'utilise quand on veut afficher du contenu uniquement si une condition est respectée. Prenons nos photos. Si l'API ne nous en retourne aucune, il serait bon d'afficher un message...

{"language":"text/html","content":"<body>\n\t<main id=\"app\">\n\t\t<h1>Les photos de l'album : {{ album }}</h1>\n\t\t<span v-if=\"photos.length < 1\">Désolé, il n'y a aucune image</span>\n\n\t</main>\n\t<script src=\"https://unpkg.com/vue@next\"></script>\n\t<script>\n\t\tconst Tutorials = {\n\t\t\tdata() {\n\t\t\t return {\n\t\t\t \talbum: 1,\n\t\t\t \tphotos:[]\n\t\t\t }\n\t\t\t},\n\t\t\tcreated() {\n\t\t\t\tfetch('https://jsonplaceholder.typicode.com/albums/1/photos')\n \t\t\t\t.then((response) => response.json())\n \t\t\t\t.then((json) => {this.photos= json});\n \t\t\t}\n\t\t}\n\t\tconst app = Vue.createApp(Tutorials).mount('#app')\n\t</script>\n</body>","filename":"index.html"}

Ici, le span ne va s'afficher QUE si la condition photos.length < 1 est respectée. Si on inspecte le code HTML de la page dans notre navigateur, on ne verra même pas notre span !

Évidemment, de la même manière que v-if, nous avons v-else et v-else-if, qui, je l'imagine, te parle assez aisément. Un petit exemple :

{"language":"text/html","content":"<body>\n\t<main id=\"app\">\n\t\t<h1>Les photos de l'album : {{ album }}</h1>\n\t\t<span v-if=\"photos.length < 1\">Désolé, il n'y a aucune image.</span>\n\t\t<span v-else>Vous trouverez dans cet album {{ photos.length }} photos. </span>\n\n\t</main>\n\t<script src=\"https://unpkg.com/vue@next\"></script>\n\t<script>\n\t\tconst Tutorials = {\n\t\t\tdata() {\n\t\t\t return {\n\t\t\t \talbum: 1,\n\t\t\t \tphotos:[]\n\t\t\t }\n\t\t\t},\n\t\t\tcreated() {\n\t\t\t\tfetch('https://jsonplaceholder.typicode.com/albums/1/photos')\n \t\t\t\t.then((response) => response.json())\n \t\t\t\t.then((json) => {this.photos= json});\n \t\t\t}\n\t\t}\n\t\tconst app = Vue.createApp(Tutorials).mount('#app')\n\t</script>\n</body>","filename":"index.html"}

À savoir que tu peux regrouper plusieurs éléments HTML qui doivent agir en fonction d'une même expression grâce à la balise template comme suit :

{"language":"text/html","content":"<template v-if=\"ma condition\">\n\t<h1></h1>\n\t<span></span>\n\t<p></p>\n\t...\n</template>","filename":""}

Tu peux bien évidemment une autre balise que template, l'avantage de cette balise c'est qu'elle est désignée pour faire ce genre de choses dans la documentation du W3C.

v-show


v-show est semblable à v-if sauf qu'au lieu de ne pas afficher l'élément dans le HTML, il va simplement lui mettre un display:none. À utiliser dans le cas où le contenu va souvent être amené à être affiché/non affiché etc. Un exemple simple et celui d'un dropdown, d'un toggle, d'une fenêtre modale...

v-bind


v-bind est l'une des directives les plus intéressantes. Elle permet de remplacer la valeur d'un attribut existant en HTML (exemple : alt, href, src...) par une donnée de Vue ! Hyper utile dans notre cas pour afficher nos photos. Elle permet aussi de faire quelques petites choses en plus que nous verrons plus tard.
Pour nos photos, du coup, on aura (attention, tant qu'on n'a pas encore notre boucle, donc je n'affiche ici qu'une seule photo) :
{"language":"text/html","content":"<body>\n\t<main id=\"app\">\n\t\t<h1>Les photos de l'album : {{ album }}</h1>\n\t\t<span v-if=\"photos.length < 1\">Désolé, il n'y a aucune image.</span>\n\t\t<span v-else>Vous trouverez dans cet album {{ photos.length }} photos. </span>\n\t\t<figure>\n\t\t\t<img v-bind:src=\"photos[0].url\" v-bind:alt=\"photos[0].title\" />\n\t\t\t<figcaption>{{ photos[0].title }}</figcaption>\n\t\t</figure>\n\n\t</main>\n\t<script src=\"https://unpkg.com/vue@next\"></script>\n\t<script>\n\t\tconst Tutorials = {\n\t\t\tdata() {\n\t\t\t return {\n\t\t\t \talbum: 1,\n\t\t\t \tphotos:[]\n\t\t\t }\n\t\t\t},\n\t\t\tcreated() {\n\t\t\t\tfetch('https://jsonplaceholder.typicode.com/albums/1/photos')\n \t\t\t\t.then((response) => response.json())\n \t\t\t\t.then((json) => {this.photos= json});\n \t\t\t}\n\t\t}\n\t\tconst app = Vue.createApp(Tutorials).mount('#app')\n\t</script>\n</body>","filename":"index.html"}

Arthur, l'apprenti développeurEt donc je ne peux pas faire <img src="{{ photos[0].url }}" ... /> ?
En effet, tu n'auras pas la possibilité de faire :

{"language":"text/html","content":"<figure>\n\t\t<img src=\"{{ photos[0].url }}\" alt=\"{{ photos[0].title }}\" />\n\t\t<figcaption>{{ photos[0].title }}</figcaption>\n</figure>","filename":""}

Si tu fais ça, tu auras une belle erreur ;)

Évidemment, ce qu'on a fait ne suffit pas à afficher nos photos. Faut-il encore faire la boucle ! C'est ce que nous allons voir juste après.

v-for


La directive v-for permet de faire une boucle. Elle s'utilise de la même manière que la boucle for(... of ...) en Javascript classique. On utilise cette directive directement sur la balise où on veut boucler, dans notre cas, c'est la balise figure.
On peut donc enfin terminer notre code.
{"language":"text/html","content":"<!DOCTYPE html>\n<html lang=\"fr\">\n<head>\n\t<meta charset=\"utf-8\">\n\t<title>Mes premiers pas avec Vue 3 : templating</title>\n</head>\n<body>\n\t<main id=\"app\">\n\t\t<h1>Les photos de l'album : {{ album }}</h1>\n\t\t<span v-if=\"photos.length < 1\">Désolé, il n'y a aucune image.</span>\n\t\t<span v-else>Vous trouverez dans cet album {{ photos.length }} photos. </span>\n\t\t<figure v-for=\"photo of photos\" :key=\"photo.id\">\n\t\t\t<img :src=\"photo.url\" :alt=\"photo.title\" />\n\t\t\t<figcaption>{{ photo.title }}</figcaption>\n\t\t</figure>\n\n\t</main>\n\t<script src=\"https://unpkg.com/vue@next\"></script>\n\t<script>\n\t\tconst Tutorials = {\n\t\t\tdata() {\n\t\t\t return {\n\t\t\t \talbum: 1,\n\t\t\t \tphotos:[]\n\t\t\t }\n\t\t\t},\n\t\t\tcreated() {\n\t\t\t\tfetch('https://jsonplaceholder.typicode.com/albums/1/photos')\n \t\t\t\t.then((response) => response.json())\n \t\t\t\t.then((json) => {this.photos= json});\n \t\t\t}\n\t\t}\n\t\tconst app = Vue.createApp(Tutorials).mount('#app')\n\t</script>\n</body>\n</html>","filename":"index.html"}


Arthur, l'apprenti développeurMais attends, pourquoi tu as mis :src et :alt et pas v-bind:src et v-bind:alt ?
Tu as l'oeil ! En fait, v-bind possède une syntaxe raccourcie. On peut simplement utiliser :alt, :href, :src plutôt que v-bind:alt, v-bind:href ou encore v-bind:src...

Arthur, l'apprenti développeurOk chouette ! Par contre, tu as utilisé cette syntaxe raccourcie sur un attribut key. Qu'est-ce que c'est ?
L'attribut key est essentiel quand on fait une boucle. Cet attribut doit contenir une valeur qui permet d'identifier de manière unique l'élément qu'on est en train de manipuler dans la boucle. Généralement, ce sera un id. Ça permet à Vue de mieux gérer des cas particuliers et ça nous permet d'assurer le bon fonctionnement des boucles.

Arthur, l'apprenti développeurEntendu. Mais si on reprend une partie précédente du tutoriel avec la donnée tutorial qui était un tableau, on n'avait pas d'identifiant unique pour chacun !
Tu parles de ce code-ci ?
{"language":"text/javascript","content":"const app = Vue.createApp({\n\t\t\tdata () {\n\t\t\t\treturn {\n\t\t\t\t\ttutorials:['Les bases de Vue 3', 'Les composants avec Vue 3', 'Aller plus loin avec Vue 3']\n\t\t\t\t}\n\t\t\t}\n\t\t}).mount('#app')","filename":""}


Arthur, l'apprenti développeurTout à fait ! Comment fait on dans ce cas ?
En fait, Vue nous permet de réécrire la boucle v-for de la manière suivante :
{"language":"text/html","content":"<li v-for=\"(tutorial, key) of tutorials\" :key=\"key\">\n\t...\n</li>","filename":""}

Évidemment, j'ai utilisé la balise <li> mais j'aurais pu utiliser n'importe laquelle. Ce qui est important, c'est le (tutorial, key). En fait, à chaque tour de boucle on va avoir un incrémenteur qu'on a appelé "key". C'est à dire que key va prendre la valeur 1, 2, 3... Ce chiffre sera unique et identifiera chacun de nos tutoriels, on peut donc s'en servir dans l'attribut du même nom.

Pendant que je suis dans la réécriture de v-for, sache que tu peux aussi écrire v-for avec "in" plutôt que "off" :
{"language":"text/html","content":"<figure v-for=\"photo in photos\" :key=\"photo.id\">\n\t\t<img :src=\"photo.url\" :alt=\"photo.title\" />\n\t\t<figcaption>{{ photo.title }}</figcaption>\n</figure>","filename":""}


C'est compris ?

Arthur, l'apprenti développeurTout est compris merci ! Mais, il n'y a que ça comme directives ?
Non, bien sûr que non. Il y en a d'autres. Nous les verrons plus tard dans la suite de ce cours. D'ailleurs, la partie juste après permettra d'en découvrir une autre.

Arthur, l'apprenti développeurAh ? Laquelle et que va-t-on faire ?
Nous allons voir la directive v-on qui permet de gérer des évènements. Le but va être de laisser la possibilité à une personne de faire une sélection de photos parmi celles affichées puis de les envoyer par email à la personne de son choix. Nous ne nous chargerons que de la partie front, l'envoie de mail ne sera donc pas effectif ;)

Arthur, l'apprenti développeurOk ça a l'air chouette ! Je suis content de voir que ce qu'on fait est très concret. Je te suis ! J'ai terminé cette partie
Demander de l'assistance