Reputation: 21
I am trying to create a Movie object from a Json output I got from an API. After each movie object is created, I add them an array of movies. All of this is inside a function and it returns the array of movies. When the function is called, I was able to console log the movies; however, when trying to get a specific item using an index, it returns undefined. Am I missing something in the code? Any help is greatly appreciated. Thanks!
function Movie(title, description, director, producer) {
this.title = title;
this.description = description;
this.director = director;
this.producer = producer;
}
var connectedToAPI = false;
function retrieveMovies() {
var movies = [];
// Create a request variable and assign a new XMLHttpRequest object to it.
var request = new XMLHttpRequest();
// Open a new connection, using the GET request on the URL endpoint
request.open('GET', 'https://ghibliapi.herokuapp.com/films', true);
request.onload = function() {
// Begin accessing JSON data here
var data = JSON.parse(this.response);
if (request.status >= 200 && request.status < 400) {
var x = 0;
data.forEach(movie => {
// var title = movie.title;
// var description = movie.description;
// var director = movie.director;
// var producer = movie.producer;
var film = new Movie(movie.title, movie.description, movie.director, movie.producer);
movies[x] = film;
x++;
});
} else {
console.log('error');
}
}
request.send();
connectedToAPI = true;
return movies;
}
var films = retrieveMovies();
if (connectedToAPI == true) {
console.log(films);
console.log(films.length);
console.log("THIS IS MOVIE NUMBER 3: ");
console.log(films[1]);
}
The console prints out:
[] //->this contains the movies when expanded
0 //->the length is zero
THIS IS MOVIE NUMBER 3:
undefined //->retrieving specific item returns udefined
Upvotes: 0
Views: 938
Reputation: 909
Your code is running BEFORE the request has come back. This is known as a "Race condition". What you want is to pass a callback to your function or promise.
Put an argument in retrieveMovies like so
function retrieveMovies(callback)
Then pass the value of movies into your callback as an arg:
callback(movies)
But do that right after your forEach completes. Your main function won't have a value immediately.
Finally, before you call your api declare a variable onFinished and set it to a function that logs your results:
var onFinished = function(films){
console.log(films);
console.log(films.length);
console.log("THIS IS MOVIE NUMBER 3: ");
console.log(films[1]);
}
retrieveMovies(onFinished);
Note that you don't set the value of retrieveMovies or check for api connection state if you use this technique.
Also, you will note that you do not need to scope your movies array so far away from your loop. Or even at all...
The better technique would be to just invoke the callback with Array.map to avoid more clutter.
Simply invoke like this (delete your forEach and var movies entirely):
callback(data.map(m=> new Movie(m.title, m.description, m.director, m.producer));
A slick one-liner :)
Upvotes: 1
Reputation: 2168
forEach is not modifying variable 'x'. It works on copies, producing undesirable effects in this case. Use a traditional for loop in cases when an index is to be accessed/used
Upvotes: 0