Travail dirigé Pokédex
Introduction
Vous allez réaliser un site web de type Pokédex en Javascript, en consommant une API de Pokémon.
Le site devra proposer :
- une page affichant la liste des Pokémon
- page suivante / précédente
- possibilité d’ajouter un Pokémon aux favoris
- une pour voir tous les favoris
- avec bouton pour tous les supprimer
Les favoris devront être sauvegardés dans le localStorage.
On va faire ça étape par étape, avec du code à trou. Pour vous aider à bien comprendre comment lire les commentaires :
/** ... **/: doit être remplacé par du code// ...: sert juste pour l’explication
Étape 1 - afficher la liste
On va utiliser une variable currentPage, qui va contenir le next, previous et results de l’API. On utilisera results pour afficher les pokémons et next et previous pour des boutons pour changer de page.
On déclare premièrement notre currentPage, on le définit à null car, pour l’instant, il n’as pas de données :
let currentPage = null;
On déclare une fonction qui s’occupera de le mettre à jour à partir d’une URL :
async function setCurrentPage(url) {
const data = await /** appel à cet URL **/;
currentPage = data;
}
Pour afficher notre liste on va créer une fonction updateList() qui aura juste pour travail de mettre à jour notre liste de pokémons actuelle :
function updateList() {
const list = getElement("list");
// pour vider la liste avant de la re-remplir
list.innerHTML = "";
for (const pokemon of currentPage.results) {
/** remplir notre liste **/
}
}
// une fonction utilitaire pour faciliter la récupération de balise
function getElement(id) {
const element = document.getElementById(id);
if (element === null) {
alert(`Aucune balise avec l'attritut : id="${id}"`);
return null;
}
return element;
}
Il nous reste plus qu’à faire une fonction qui s’occupe de mettre à jour le currentPage puis de mettre à jour le HTML :
async function loadListPage(url) {
await /** définir currentPage **/;
/** mettre à jour la liste **/;
}
loadListPage("https://pokeapi.co/api/v2/pokemon");
Et normalement, une liste de noms de pokémons devrait apparaître.
Ajoutons maintenant les boutons pour changer de page. La logique reste simple, on récupère nos deux boutons puis, s’il il n’y a pas de lien pour la page précédente/suivante, on affichera une alerte, sinon on appel notre fonction qui met à jour toute la page :
function updateButtons() {
const previous = /** récupérer le bouton 'précédent' **/;
const next = /** récupérer le bouton 'suivant' **/;
if (currentPage.previous === null) {
previous.onclick = () => alert("Pas de page précédente");
} else {
previous.onclick = () => /** charger la page avec l'URL dans currentPage.previous **/;
}
if (currentPage.next === null) {
next.onclick = () => alert("Pas de page suivante");
} else {
next.onclick = () => /** charger la page avec l'URL dans currentPage.next **/;
}
}
Étape 2 - gestion des favoris
Avant toute chose, dans votre code, vous devez avoir une ligne du style :
loadListPage("https://pokeapi.co/api/v2/pokemon");
Cette ligne permet de charger la page de liste au moment où le Javascript est chargé, ce qui veut dire que la fonction sera aussi appelée si on utilise le même script.js dans notre autre page pour les favoris, et ce n’est pas ce qu’on veut. Une solution très simple est de l’enlever de script.js et de transformer votre balise <script> et de la déplacer après le <body> :
<body>
...
</body>
<script src="script.js"></script>
<script>
loadListPage("https://pokeapi.co/api/v2/pokemon");
</script>
Ça marche exactement pareil, mais ça nous permet d’utiliser le même fichier pour d’autre page sans qu’il charge la liste de pokémons automatiquement.
Maintenant, la gestion de nos favoris se fait en trois étapes, gérer les favoris avec des boutons dans la page d’accueil, pouvoir les voir et les gérer dans une page /favorites.html et enfin les sauvegarder dans le localStorage.
Étape 2.1 - gestion des favoris dans la page d’accueil
Pour “retenir” les favoris, on ne va pas sauvegarder les pokémons en entier pour 2 raisons :
- c’est lourd (même si à cette échelle c’est ridicule), l’API a juste besoin de leur nom pour qu’elle nous restitue toutes les informations d’un pokémon
- si la donnée sur le pokémon a changé dans l’API, on gardera une ancienne version du pokémon
Pour ce faire, on déclare une deuxième variable pour retenir la liste de favoris, qui par défaut sera un tableau vide (aucun favoris) :
let favorites = [];
On commence par une première fonction qui aura pour but d’activer/désactiver (toggle) un pokémons en favoris, le principe est simple, si le nom est déjà dans la liste, on l’enlève, sinon on l’ajoute :
function toggleFavorite(name) {
const alreadyExists = favorites.find((curr) => curr === name);
if (alreadyExists) {
favorites = favorites.filter((curr) => curr !== name);
} else {
/** ajouter name au favorites **/;
}
}
Il nous faut également une fonction parent, qui aurait pour but d’activer/désactiver un favoris puis de mettre à jour le HTML :
function handleFavorite(name) {
/** activer/desactiver un favoris par son nom **/;
/** mettre à jour la liste **/;
}
Pour se simplifier la vie, on va également écrire une fonction qui aura pour but de nous renvoyer l’HTML d’un bouton adapté en fonction du nom du pokémon :
- s’il existait déjà : un bouton “Supprimer des favoris”
- sinon : un bouton “Ajouter au favoris”
function getFavoriteButton(name) {
const isFavorite = favorites.find((curr) => curr === name);
let message = "Ajouter aux";
if (isFavorite) {
message = "Supprimer des"
}
return `<button onclick="handleFavorite('${name}')">${message} favoris</button>`;
}
Maintenant qu’on a notre générateur de bouton, on peut l’utiliser directement là ou on remplit la liste de pokémons :
for (const pokemon of currentPage.results) {
const button = /** récupérer le bouton à partir du nom du pokémon **/;
const li = /** <li> avec le nom du pokemon et le bouton **/;
list.innerHTML += li;
}
Et normalement, un bouton apparaît après chaque nom de pokémon, et quand vous cliquez sur l’un d’entre eux, vous pouvez le voir switcher d’état.
Étape 2.2 - sauvegarde dans le localStorage
Nos favoris se réinitialisent dès qu’on rafraîchit la page, il faut les rendre persistant, pour ce faire, c’est très simple. Il faut dans un premier temps mettre notre tableau de favoris à vide, et s’il existe une sauvegarde dans le localStorage, on l’utilise :
let favorites = [];
const savedFavorites = /** récupérer les favorites du localStorage **/;
if (savedFavorites) {
favorites = /** les favoris sauvegardés **/;
}
Il faut également penser à sauvegarder dans le localStorage chaque modification apportée aux favorites, heureusement, les seules modifications sont faites uniquement dans la fonction toggleFavorite(), on a donc juste besoin d’ajouter une sauvegarde à la fin de la fonction :
save("favorites", favorites);
Étape 2.3 - page des favoris
À partir de tout ce qui a été fait précédemment, vous êtes capable de réaliser une page pour les favoris. Il s’agit de la même liste (nom + bouton), mais basé sur favorites (et non currentPage.results).
Étape 3 - single page
Pour l’instant, on affiche que le nom du pokémons, mais ça serait sympa d’afficher plus d’information sur une page. Bien évidemment, on va pas faire une page par pokémon, mais une seule page qui gère tous les pokémons, une single page.
Vous pouvez donc créer un fichier pokemon.html qui contiendra notre code HTML qui sera accéder avec /pokemon.html?name=pikachu comme style d’URL. Et voici comment est-ce qu’on peut récupérer le name dans l’URL :
function getNameInUrl() {
const params = new URLSearchParams(window.location.search);
const name = params.get("name");
return name;
}
const name = getNameInUrl();
console.log(name);
Et à partir de ce name, on peut récupérer le pokémon associé :
async function getPokemon(name) {
const pokemon = await call(`https://pokeapi.co/api/v2/pokemon/${name}`);
return pokemon;
}
async function test() {
const pokemonName = getNameInUrl();
const pokemon = await getPokemon(pokemonName);
console.log(pokemon);
}
test();
Vous verrez dans votre console toutes les informations que renvoie l’API. Pour essayer, pensez à créer un lien dans le <li> de chaque pokémon, avec l’attribut href="pokemon.html?name=${pokemon.name}".
Et à partir de ça, on peut se créer une fonction qui insert du HTML dans la page :
function displayPokemon(pokemon) {
const section = /** récupérer la balise dans laquelle afficher le pokémon **/;
section.innerHTML = `<h1>${pokemon.name}</h1>
<p>Hauteur : ${pokemon.height}</p>
<p>Poids : ${pokemon.weight}</p>
<img src="${pokemon.sprites.front_default}" alt="image de ${pokemon.name}" />`;
}
N’hésitez pas à regarder toutes les informations que vous donne l’API pour en afficher plus si vous le souhaitez.
Il ne manque plus qu’à modifier notre affichage de liste, dans les autres pages :
const li = /** votre ancien li + un lien redirigeant vers : pokemon.html?name=NOM_DU_POKEMON **/;
Et à ajouter une fonction pour charger le pokémon à l’ouverture de la page :
async function loadPokemon() {
const pokemonName = /** récupérer le nom depuis l'URL **/;
const pokemon = await /** récupérer le pokémon à partir du nom **/;
/** afficher le pokémon **/;
}
Il vous suffit d’appeler cette fonction à la fin du chargement de la page, et ça fonctionne.
Étape 4 - UI et UX
UI signifie User Interface, il désigne la partie purement esthétique d’un site web, contrairement à l’UX, soit User Experience, toute la partie praticité. Un site web peut être très beau, mais ignoble à utiliser, il aurait alors une bonne UI mais une très mauvaise UX.
Vous l’avez constaté, ce cours ne vous aide que sur la logique métier (et un peu l’UX). Vous devez maintenant rendre votre site web esthétique tout en le gardant pratique.