Reputation: 283
I'm working on a small Javascript application that uses an API from pokeapi.co. Basically, it is supposed to fetch a few datas from the API and then display them on an HTML page. Here is the main part of the code :
const searchInput= document.querySelector(".recherche-poke input");
let allPokemon= [];
let tableauFin= [];
const listePoke= document.querySelector('.liste-poke');
function fetchPokemonBase(){
fetch("https://pokeapi.co/api/v2/pokemon?limit=75")
.then(reponse => reponse.json())
.then((allPoke) =>{
allPoke.results.forEach((pokemon) =>{
fetchPokemonComplet(pokemon);
})
})
}
fetchPokemonBase();
function fetchPokemonComplet(pokemon){
let objPokemonFull = {};
let url = pokemon.url;
let nameP = pokemon.name;
fetch(url)
.then(reponse => reponse.json())
.then((pokeData) => {
objPokemonFull.pic = pokeData.sprites.front_default;
objPokemonFull.type = pokeData.types[0].type.name;
objPokemonFull.id = pokeData.id;
fetch(`https://pokeapi.co/api/v2/pokemon-species/${nameP}`)
.then(reponse => reponse.json())
.then((pokeData) => {
objPokemonFull.name= pokeData.names[4].name;
allPokemon.push(objPokemonFull);
if(allPokemon.length === 75){
tableauFin= allPokemon.sort((a, b) => {
return a.id - b.id;
}).slice(0, 21);
createCard(tableauFin);
}
})
});
}
function createCard(arr){
for(let i= 0; i< arr.length; i++){
console.log(i + '\n');
const carte= document.createElement("li");
const txtCarte= document.createElement('h5');
txtCarte.innerText= arr[i].name;
const idCarte= document.createElement('p');
idCarte.innerText= `ID# ${arr[i].id}`;
const imgCarte= document.createElement('img');
imgCarte.src= arr[i].pic;
carte.appendChild(imgCarte);
carte.appendChild(txtCarte);
carte.appendChild(idCarte);
listePoke.appendChild(carte);
}
}
Here's what the code does : it gather a list of 75 pokemons from the pokeapi API. Then it fetches the data about each pokemon from the same site and stores each data into one element of the allPokemon
array, when the length of this array reaches 75, we begin to create the HTML elements to display the data.
The ambigious part here is :
if(allPokemon.length === 75){
tableauFin= allPokemon.sort((a, b) => {
return a.id - b.id;
}).slice(0, 21);
createCard(tableauFin);
}
This code works but only when none of the requests fail. Otherwise, the length of the array allPokemon
never reaches 75 and the rest of the code won't be executed. When I run the code, I run on XHR GET errors and the script stops before displaying the datas and it's (I think) what caused one of the promises to fail. I tried things like if(allPokemon.length === 74)
(if I have one error, for example) and the code works just fine but that is surely not the solution.
Is there a way for me to "count" the errors I get from my requests so that I can do something like if(allPokemon.length === 75 - errorsCount)
or maybe there is a smarter way to write my code?
Thanks in advance.
Upvotes: 1
Views: 362
Reputation: 26
I think you can use promise all for this. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
function fetchPokemonBase(){
const promises = []
fetch("https://pokeapi.co/api/v2/pokemon?limit=75")
.then(reponse => reponse.json())
.then((allPoke) =>{
allPoke.results.forEach((pokemon) =>{
promises.push(fetchPokemonComplet(pokemon).catch(error => console.error(error)));
})
})
.then(() => {
Promise.all(promises)
.then(() => {
tableauFin= allPokemon.sort((a, b) => {
return a.id - b.id;
}).slice(0, 21);
createCard(tableauFin);
})
})
}
fetchPokemonBase();
let counter = 0
function fetchPokemonComplet(pokemon){
let objPokemonFull = {};
let url = pokemon.url;
let nameP = pokemon.name;
return fetch(url)
.then(reponse => reponse.json())
.then((pokeData) => {
counter++;
objPokemonFull.pic = pokeData.sprites.front_default;
objPokemonFull.type = pokeData.types[0].type.name;
objPokemonFull.id = pokeData.id;
return fetch(`https://pokeapi.co/api/v2/pokemon-species/${nameP}`)
.then(reponse => reponse.json())
.then((pokeData) => {
objPokemonFull.name= pokeData.names[4].name;
allPokemon.push(objPokemonFull);
})
});
}
So what you do is, instead of executing the fetch in the foreach, we push each fetch to an array of promises. Then we use the promise.all to execute them, and for each promise we catch the errors. So if one fails, the next promise will just continue.
With this code we push every fetch for the individual pokemons to an array:
promises.push(fetchPokemonComplet(pokemon).catch(error => console.error(error)));
Then we have an array of promises, which are the fetches to the server. With the following code we execute these promises.
Promise.all(promises)
.then(() => {
tableauFin= allPokemon.sort((a, b) => {
return a.id - b.id;
}).slice(0, 21);
createCard(tableauFin);
})
the then on promise.all will be executed when all the promises are done. And since we catch on every individual promise we don't have to worry about that. And we don't care about the length and don't have to keep count. Let me know if it works, or need any help.
Upvotes: 1
Reputation: 21
From what I see, you will receive a list of between 0 and 75 pokemons from the first API call. Then, you fetch each one, however many it returned, up to 75 entries.
So, I think you want to just make sure your list isn't empty:
if(allPokemon.length > 0)
Upvotes: 0