im using fetch to get informations, sometimes it shows everything well, sometimes if shows nothing everything is undefined, and sometimes it shows some data well with some data as undefined. the images shows my issue:
and thats my code:
// fetch the movies from api
class Movie {
constructor(id) {
this.id = id;
this.load();
}
finalize(json) {
this.name = json.original_title;
this.img = json.poster_path;
this.link = name.replace(/[^a-zA-Z\s/ ]/g, "");
var MyArray = {
'name': `${this.name}`,
'img': `${this.img}`,
'link': `/movies/${this.link}.html`
}
console.log(MyArray)
}
load() {
fetch(`https://api.themoviedb.org/3/movie/${this.id}?api_key=a913ee104db6b795d20852a9ed989036`)
.then((res) => res.json())
.then((json) => {
this.finalize(json)
})
.catch(err => {
console.error(err);
});
}
}
// The array of movies
const MyMovies = [
new Movie(238),
new Movie(899082),
new Movie(899),
]
// show the movies in the page
function LoadMovies() {
var table = document.querySelector('#movies')
for (var i = 0; i < MyMovies.length; i ) {
var item = MyMovies[i];
var row = `<img id="img" src="${'https://image.tmdb.org/t/p/w185/' item.img}" alt="${item.name}" onclick="location.href='${"movies/" item.link ".html"}'">`
table.innerHTML = row
}
}
CodePudding user response:
You can wait until all movies are initialized:
// fetch the movies from api
class Movie {
constructor(id) {
this.id = id;
this.isInitialized = this.load();
}
finalize(json) {
this.name = json.original_title;
this.img = json.poster_path;
this.link = name.replace(/[^a-zA-Z\s/ ]/g, "");
var MyArray = {
'name': `${this.name}`,
'img': `${this.img}`,
'link': `/movies/${this.link}.html`
}
console.log(MyArray)
}
load() {
return fetch(`https://api.themoviedb.org/3/movie/${this.id}?api_key=a913ee104db6b795d20852a9ed989036`)
.then((res) => res.json())
.then((json) => {
this.finalize(json)
})
.catch(err => {
console.error(err);
});
}
}
// The array of movies
const MyMovies = [
new Movie(238),
new Movie(899082),
new Movie(899),
]
// show the movies in the page
async function LoadMovies() {
var table = document.querySelector('#movies');
await Promise.all(MyMovies.map(movie => movie.isInitialized));
for (var i = 0; i < MyMovies.length; i ) {
var item = MyMovies[i];
var row = `<img id="img" src="${'https://image.tmdb.org/t/p/w185/' item.img}" alt="${item.name}" onclick="location.href='${"movies/" item.link ".html"}'">`
table.innerHTML = row
}
}
LoadMovies();
<table id="movies">
</table>
CodePudding user response:
The constructor doesn't wait for the fetch to complete, so you're trying to use all the Movie
objects before the information has been fetched. There's no way to await a class constructor, because it always returns a class instance, not a promise (see Async/Await Class Constructor).
Instead of calling this.load()
in the constructor, do it in the loop.
class Movie {
constructor(id) {
this.id = id;
}
finalize(json) {
this.name = json.original_title;
this.img = json.poster_path;
this.link = name.replace(/[^a-zA-Z\s/ ]/g, "");
var MyArray = {
'name': `${this.name}`,
'img': `${this.img}`,
'link': `/movies/${this.link}.html`
}
console.log(MyArray)
}
load() {
fetch(`https://api.themoviedb.org/3/movie/${this.id}?api_key=a913ee104db6b795d20852a9ed989036`)
.then((res) => res.json())
.then((json) => {
this.finalize(json)
})
.catch(err => {
console.error(err);
});
}
}
// The array of movies
const MyMovies = [
new Movie(238),
new Movie(899082),
new Movie(899),
]
// show the movies in the page
async function LoadMovies() {
var table = document.querySelector('#movies')
for (var i = 0; i < MyMovies.length; i ) {
var item = MyMovies[i];
await item.load();
var row = `<img id="img" src="${'https://image.tmdb.org/t/p/w185/' item.img}" alt="${item.name}" onclick="location.href='${"movies/" item.link ".html"}'">`
table.innerHTML = row
}
}