Film finder project challenge - Display liked movie to page

I’m trying to implement one of the project extension suggested at the end of the Film Finder project: Create a way to store a user’s liked and disliked movies and display this list on the page.

I think I’m half way there, but I’m running into some issues and reached a point where I would need some advice to get it to work.

I tried two different ways that I will link below - the code can be found helpers.js. I added 2 functions addToLikedMovies and displayLikedMovies, and added some HTML. I also left some comments in each version.

Version 1:
https://www.codecademy.com/workspaces/626e4da55fc8977efa5fc462

In this version, when I log the movieInfo (passed to the function from displayMovie()), I get a PointerEvent object. Similarly, when I log the likedMovies array, I get a PointerEvent array. The text showing on screen is thus undefined.

Screenshot 2022-05-01 at 11.42.42

I think this might have to do with likeBtn.onclick = likeMovie; in displayMovie()? I’m not sure it receives the movieInfo argument since it’s a function reference, and if I do likeBtn.onclick = likeMovie(movieInfo) the movies are added endlessly as soon as Play is clicked.

Version2:
https://www.codecademy.com/workspaces/626e4eceac46cff76f1a1658

In this version, I used likeBtn.addEventListener('click', () => { likeMovie(movieInfo) }); instead.
This time with the same console.log as version 1, I do see the movie data, but it’s not added to the movies cumulatively in one array as I want. After liking a second movie and then a couple more, the behaviour becomes worse :exploding_head::

As you can see I end up with more and more arrays containing only one movie, and the same movie populates several of those arrays multiple times the more I click Like. Next to that, the API also starts fetching 3-4 movies instead of one. :face_with_peeking_eye:

I think this might be due to attaching the event listener to the like button from within the displayMovie() function? Should it be removed at some point, and where?

Hopefully someone can hint me towards what I’m doing wrong.

Yes, you’re adding a new event listener each time displayMovie() runs. That’s a problem if you’re not eliminating the old one.

You could put that event listener at the end, outside the displayMovie function, but that would require a creating an object for the movieInfo argument if you don’t change any other code:

const getMovieInfoFromPage() {
    const poster_path = document.querySelector("#moviePoster img").src;
    const title = document.getElementById("movieTitle").innerText;
    const overview = document.getElementById("movieOverview").innerText;
    return { poster_path, title, overview };  // object like movieInfo in displayMovie function
}

likeBtn.addEventListener('click', () => {
     likeMovie(getMovieInfoFromPage());
});
dislikeBtn.onclick = () => { dislikeMovie(getMovieInfoFromPage()) };

Alternatively, you could use onclick instead inside of the displayMovie function, because onclick only contains one event listener function.
(For this option, you can’t call showRandomMovie in the likeMovie function, because that calls displayMovie, resulting in a possibly infinite loop of function calls.)

  likeBtn.onclick = () => { likeMovie(movieInfo) };
  dislikeBtn.onclick = () => { dislikeMovie(movieInfo) };

you can’t just do likeBtn.onclick = likeMovie because, for onclick, the argument of the function would be an event object ( … in this case a mouse pointer event, because it would be a click event).

2 Likes

Hi Jan and thanks for your response!

likeBtn.onclick = () => { likeMovie(movieInfo) };
dislikeBtn.onclick = () => { dislikeMovie(movieInfo) };
you can’t just do likeBtn.onclick = likeMovie because, for onclick , the argument of the function would be an event object ( … in this case a mouse pointer event, because it would be a click event).

This is the explanation I needed, thank you!! Actually I had no idea I could assign the function this way… I opted for this solution in the end, as it looks a bit cleaner.

(For this option, you can’t call showRandomMovie in the likeMovie function, because that calls displayMovie , resulting in a possibly infinite loop of function calls.)

I actually don’t understand how this would cause an infinite loop - since we only trigger likeMovie() when clicking on the like button, then is it not “safe”? (Also I just left the call to showRandomMovie in the likeMovie function for now and I don’t see any symptom of that so far)

The only remaining thing that I wanted to fix was the array of liked movies, I was only able to create a brand new array with a new movie inside at each like click instead of one single array (even if the li elements were displaying correctly). I declared the array as a global variable instead and also made a conditional to remove all children li before creating new ones. Something you also mentioned in your comment before editing, very helpful. :slight_smile:

const likedMovies = [];

// Add movie to list of liked movies
const addToLikedMovies = (movieInfo) => {
  likedMovies.push(movieInfo);
  displayLikedMovies(likedMovies);
};

// Show liked movies at the bottom of page
const displayLikedMovies = (likedMovies) => {
  // Grabs the ul element
  const movieList = document.getElementById('likedMoviesList');
  // Checks if the ul has li children
  if (movieList.hasChildNodes()) {
    // Clear all children li before creating new ones for each movie in our likedMovies array
    while (movieList.firstChild) {
      movieList.removeChild(movieList.firstChild);
    }
  }
  likedMovies.forEach((movie) => {
    const title = document.createElement('li');
    title.classList.add('likedMovie');
    title.setAttribute('id', 'likedMovie');
    title.innerText = movie.title;
    movieList.appendChild(title);
  });
};

Thanks again for taking the time to help me!

2 Likes