Commentaires
Antoine Creuzet
04/04/2022 à 10:56
Bonjour Bruno Ramael. Après vérifications, je n'ai pas de soucis avec le code fourni. Disponible pour en discuter sur le Discord avec l'assistance :)
Bruno Ramael
25/02/2022 à 11:49
Si on utilise l'url de l'api donné par la nasa, on a plus une list mais un objet unique. Ainsi j'ai du corriger le script et mettre return this.photos = [result] et non return this.photos = result
Bruno Ramael
25/02/2022 à 10:58
Bonjour, si on remplace notre key dans l'url api on a le message d'erreur: API_KEY_MISSING No api_key was supplied. Get one at https://api.nasa.gov:443
J'ai décidé de nommer ce projet "Prenons de la hauteur". Effectivement, comme je le disais précédemment, le projet consistera en une application permettant de laisser des avis et de noter des photos. Mais pas n'importe lesquelles ! Des photos de la planète Mars, prises par les rovers Curiosity ou encore Spirit. Ou bien des photos élues par la NASA prises par des amateurs, des télescopes...
Pour chaque photo on aura donc une liste d'avis et un formulaire pour déposer le sien.

Arthur, l'apprenti développeurTrop classe ! Mais attends, comment tu fais pour récupérer ces photos ?
Surprise surprise ;)

Récupération des photos


La NASA met à disposition une API qui permet de récupérer ces photos. Il y a plein d'API super intéressantes. Je te propose ici deux API disponibles à utiliser. Une qui permet de récupérer les photos prises par des rovers sur Mars, l'autre qui permet de récupérer les "photos du jour" prises par des télescopes, des amateurs, etc. Durant tout le tutoriel j'utiliserai la clé d'API (c'est à dire la clé qui permet de se connecter à l'API) de démo. On est limité à 50 appels d'API par IP par jour. Si tu en veux plus, tu peux te créer un compte. Voici le lien pour avoir la documentation et toutes les informations utiles : https://api.nasa.gov.
Petite anecdote : j'aurais bien aimé utiliser des photos proposées par ArianeSpace ou l'Agence Spatiale Européenne, malheureusement il n'y a pas, à ma connaissance, d'API simple d'utilisation pour récupérer ces données.

Code type pour utilisation de l'API concernant les rovers


Voici le code type que tu pourras utiliser si tu souhaites utiliser les photos de Curiosity qui patrouille sur Mars.

{"language":"text/html","content":"<template>\n <figure v-for=\"photo in photos\" :key=\"photo.id\">\n <img :src=\"photo.img_src\" />\n </figure>\n</template>\n\n<script>\nconst API_URL = 'https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?&page=1&sol=1000&api_key=DEMO_KEY'\nexport default {\n name: 'App',\n data() {\n return {\n photos: []\n }\n },\n created() {\n fetch(API_URL)\n .then(result => result.json())\n .then(result => {this.photos = result.photos})\n }\n}\n</script>","filename":"App.vue"}

Code type pour utilisation de l'API concernant les "photos of the day"


Et voici donc le deuxième code type :

{"language":"text/html","content":"<template>\n <figure v-for=\"photo in photos\" :key=\"photo\">\n <img :src=\"photo.url\" :alt=\"photo.title + 'prise par' +photo.copyright\" />\n <figcaption>\n <h2>{{ photo.title }} prise le {{ photo.date }}</h2>\n <p>{{ photo.explanation }}</p>\n </figcaption>\n </figure>\n</template>\n\n<script>\nconst API_URL = 'https://api.nasa.gov/planetary/apod?start_date=2021-02-01&end_date=2021-02-17&api_key=DEMO_KEY'\nexport default {\n name: 'App',\n data() {\n return {\n photos: []\n }\n },\n created() {\n fetch(API_URL)\n .then(result => result.json())\n .then(result => {this.photos = result})\n }\n}\n</script>\n","filename":"App.vue"}

Pour ma part durant ce cours je vais utiliser ce deuxième code. Il me semble plus intéressant (et les photos sont plus diversifiées :p).

Arthur, l'apprenti développeurSuper ces API ! Je ne savais pas que la NASA mettait à disposition ces photos !
Si, et je trouvais intéressant de les utiliser justement. Ça change un peu des photos banales de service de fake API !

Arthur, l'apprenti développeurJe suis bien d'accord. Petite question concernant le deuxième code : pourquoi tu as mis :key="photo" et pas :key="photo.id" ?
En fait si on regarde le résultat de notre API, les photos n'ont pas d'id ! Du coup pour identifier la photo dans la boucle, je mets directement l'objet entier de :key. C'est quelque chose qui est licite, on retrouve parfois cette façon de faire dans la documentation de Vue.JS. On aurait pu également faire v-for="(photo, key) in photos" comme d'habitude et faire :key="key" évidemment.

Arthur, l'apprenti développeurD'accord ! Bon du coup je vais utiliser le deuxième code, comme toi. Mais si je décide de reprendre le cours avec le premier, tout va marcher pareil ?
Il faudra faire quelques adaptations, mais rien de bien grave. Ce sera d'ailleurs un très bon exercice pour vérifier si tu as compris le cours de le reprendre avec une autre API de la NASA (donc mon premier code par exemple). Cela te permettra également de laisser libre cours à ton imagination pour les fonctionnalités, les composants...

Arthur, l'apprenti développeurEntendu ! D'ailleurs, en terme de composants, on va s'organiser comment ?
Excellente question. Excellente question qu'il faut se poser dès maintenant !

Le choix de nos composants


Déjà, il faut bien comprendre que lorsque je parle de composants, je parle maintenant de SFC. On n'utilisera que cette "syntaxe" pour les composants.

Maintenant se pose la question : quels composants ? Comment fais-je pour savoir ce que je peux déléguer à des composants ?
Tu as une idée ?

Arthur, l'apprenti développeurPeut être par rapport aux fonctionnalités ? Je veux dire, si on a une fonctionnalité qu'on veut réutiliser plusieurs fois, on peut en faire un composant ?
Oui en effet. Nous avons un composant simple à deviner dans notre cas : le composant "Photo". Et ce pour des raisons pratiques au delà de raisons de réutilisation. Imaginons qu'on veuille modifier la date de la photo pour qu'elle ait un format français. On utilisera une computed property (CP). Et une CP s'utilise sur un élément en particulier, pas sur un array. J'entends par là qu'à l'heure actuelle, on ne peut pas faire ça :

{"language":"text/html","content":"<h2>{{ photo.title }} prise le {{ dateFormatted }}</h2>","filename":"App.vue"}

Puisqu'on ne peut pas créer une CP pour une liste. On peut à la limite faire la chose suivante :

{"language":"text/html","content":"<template>\n <figure v-for=\"photo in photos\" :key=\"photo\">\n <img :src=\"photo.url\" :alt=\"photo.title + 'prise par' +photo.copyright\" />\n <figcaption>\n <h2>{{ photo.title }} prise le {{ formattedDate(photo) }}</h2>\n <p>{{ photo.explanation }}</p>\n </figcaption>\n </figure>\n</template>\n\n<script>\nconst API_URL = 'https://api.nasa.gov/planetary/apod?start_date=2021-02-01&end_date=2021-02-17&api_key=DEMO_KEY'\nexport default {\n name: 'App',\n data() {\n return {\n photos: []\n }\n },\n created() {\n fetch(API_URL)\n .then(result => result.json())\n .then(result => {this.photos = result})\n },\n methods: {\n formattedDate(photo) {\n let date = new Date(photo.date)\n let day = Number(date.getDate()) >= 10 ? date.getDate() : '0'+date.getDate()\n return `${day}/${date.getMonth()}/${date.getFullYear()}`\n }\n }\n}\n</script>","filename":"App.vue"}

Mais c'est moins propre. Il est donc évident qu'on utilisera un composant pour nos photos. La logique est la même pour le formulaire des avis pour chaque photo : on mettrait un v-model comment ? Si on utilise le code ci-dessous, on aura le même avis qui sera rempli pour toutes les photos...

{"language":"text/html","content":"<figcaption>\n <h2>{{ photo.title }} prise le {{ formattedDate(photo) }}</h2>\n <p>{{ photo.explanation }}</p>\n\t<textarea v-model=\"avis\"></textarea>\n</figcaption>","filename":"App.vue"}

Tu comprends le problème ?

Arthur, l'apprenti développeurOui je crois. Étant donné qu'on veut agir sur une seule photo à la fois dans chaque cas tu me cites, il vaut mieux déléguer ça à un composant.
C'est tout à fait juste. Tu peux te demander si tu as besoin d'un composant quand tu te verras utiliser dans tes templates des choses suivantes :

{"language":"text/html","content":"<button @click=\"doSomethingOn(element)\"></button>\n<!-- ou -->\n<input v-model=\"avis[element.id]\">\n<!-- ... -->","filename":"App.vue"}

De manière plus générale (mais pas 100% vraie), dès que tu boucles sur des éléments, tu peux te demander si tu as besoin d'un composant.

Arthur, l'apprenti développeurOk c'est noté. Mais il n'y a que ça comme cas d'utilisation d'un composant ?
Non. Il n'y a pas de science exacte du composant, mais en général ça se "sent" quand on en a besoin. On peut aussi découper toute notre application sous forme de composants pour des raisons de flexibilité, maintenabilité. Il est par exemple recommandé par TailwindCSS (http://tailwindcss.com) d'utiliser des composants pour chacun des éléments du design qui sont amenés à être réutilisés. Par exemple une navbar, des boutons, des cards...

Arthur, l'apprenti développeurEntendu. On peut donc commencer à créer nos composants ?
Tout à fait.

La création de nos composants


On va donc créer notre composant Photo. Je te laisse créer un nouveau fichier Photo.vue qu'on mettra dans le dossier "components".

{"language":"text/html","content":"<template>\n <figure>\n <img :src=\"photo.url\" :alt=\"photo.title + 'prise par' +photo.copyright\" />\n <figcaption>\n <h2>{{ photo.title }} prise le {{ formattedDate }}</h2>\n <p>{{ photo.explanation }}</p>\n </figcaption>\n </figure>\n</template>\n\n<script>\n export default {\n computed: {\n formattedDate() {\n let date = new Date(photo.date)\n let day = Number(date.getDate()) >= 10 ? date.getDate() : '0'+date.getDate()\n return `${day}/${date.getMonth()}/${date.getFullYear()}`\n }\n }\n }\n</script>\n\n<style>\n\n</style>","filename":"Photo.vue"}

{"language":"text/html","content":"<template>\n <photo v-for=\"photo in photos\" :key=\"photo\"></photo>\n</template>\n\n<script>\nimport Photo from './components/Photo.vue'\nconst API_URL = 'https://api.nasa.gov/planetary/apod?start_date=2021-02-01&end_date=2021-02-17&api_key=DEMO_KEY'\nexport default {\n name: 'App',\n components: {\n Photo\n },\n\n data() {\n return {\n photos: [],\n }\n },\n created() {\n fetch(API_URL)\n .then(result => result.json())\n .then(result => {this.photos = result})\n }\n}\n</script>\n","filename":"App.vue"}

Arthur, l'apprenti développeurAh on peut mettre v-for sur un composant ?
Tout à fait ! C'est comme une autre balise ;)

Par contre, si tu mets tout ça en place, tu auras l'erreur suivante :


Arthur, l'apprenti développeurComment ça photo est undefined dans mon composant ?
Hé bien oui, en réalité, même si on a fait le v-for sur <photo> notre composant lui n'a pas accès à ces données.

Arthur, l'apprenti développeurAlors comment va-t-on faire ?
On va devoir lui passer. Et ce grâce aux props. On voit ça justement dans le chapitre suivant ;) J'ai terminé cette partie
Demander de l'assistance