The Code
const API_KEY = "SECRET";
// Calls the API and gets the movies, async tells it to wait, returns movie array
async function getMovies() {
// attempt to get all the popular movies through API
try {
let response = await fetch('https://api.themoviedb.org/3/movie/popular', {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
});
// changes the string recieved back and parses it into an object
let data = await response.json();
return data.results;
// if something goes wrong, show error alert
} catch (error) {
swal.fire({
icon: 'error',
backdrop: false,
title: 'Oops!',
text: 'Something went wrong reaching the TMBD API.'
})
}
}
// Calls the API and gets information for the one movie
async function getMovie(movieId) {
// Attempt to get movie details through API
try {
let response = await fetch(`https://api.themoviedb.org/3/movie/${movieId}`, {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
});
// changes the string recieved back and parses it into an object
let data = await response.json();
return data;
// if something goes wrong, show error alert
} catch (error) {
swal.fire({
icon: 'error',
backdrop: false,
title: 'Oops!',
text: 'Something went wrong reaching the TMBD API.'
})
}
}
// Shows all the movie cards on the page
function displayMovies(movies) {
// Get the div that the movie cards will be placed into
const movieListDiv = document.getElementById('movie-list');
// Initialize the DIV, make sure it's empty
movieListDiv.textContent = '';
// Get the template for the movie cards
const moviePosterTemplate = document.getElementById('movie-card-template');
// Create the movie card from the template for each movie returned in the list
for (let i = 0; i < movies.length; i++) {
let movie = movies[i];
// Copy everything in template tags
let movieCard = moviePosterTemplate.content.cloneNode(true);
// Uses a CSS selector to get the element and reassign the value of the img src attribute
let movieImgElement = movieCard.querySelector('.card-img-top');
movieImgElement.src = `https://image.tmdb.org/t/p/w500${movie.poster_path}`
// Get the element holding the movie title and replace the text with the title of the movie
let movieTitleElement = movieCard.querySelector('.card-body > h5');
movieTitleElement.textContent = movie.title;
// Get the element holding the paragraph information and replace the text with the summary of movie
let movieParagraphElement = movieCard.querySelector('.card-text');
movieParagraphElement.textContent = movie.overview;
// Make up own attribute to assign movie id to access this information later for the modal
let movieButton = movieCard.querySelector('.btn-primary');
movieButton.setAttribute('data-movieId', movie.id);
// Add the movie card to the page
movieListDiv.appendChild(movieCard);
}
}
// Get the list of movies with no filter and put them on the page
async function displayAllMovies() {
let movies = await getMovies();
displayMovies(movies);
}
// Put the movie details in the modal when "More Info" button is pressed
async function showMovieDetails(clickedBtn) {
// get the ID of the movie that was clicked
let movieId = clickedBtn.getAttribute('data-movieId');
// get the details of the movie with that ID from TMBD API
let movieData = await getMovie(movieId);
// Modify Img on Modal
let movieImg = document.querySelector('#movieModal .movie-image');
movieImg.src = `https://image.tmdb.org/t/p/w500${movieData.poster_path}`
// Modify Title on Modal
let modalTitle = document.querySelector('#movieModal .movie-title');
modalTitle.textContent = movieData.title;
// Modify Tagline on Modal
let modalTagline = document.querySelector('#movieModal .tagline');
modalTagline.textContent = `${movieData.tagline}`;
// Display genres on page
displayGenres(movieData.genres);
// Modify overview summary of Modal
let modalBody = document.querySelector('#movieModal .overview');
modalBody.textContent = movieData.overview;
// Modify homepage website button links to on Modal
let moviePageBtn = document.querySelector('#movieModal .btn-primary');
moviePageBtn.href = movieData.homepage;
// Modify Release Date
let releaseDateMonth = document.getElementById('month');
releaseDateMonth.textContent = movieData.release_date.slice(5,7);
let releaseDateDay = document.getElementById('day');
releaseDateDay.textContent = movieData.release_date.slice(8,10);
let releaseDateYear = document.getElementById('year');
releaseDateYear.textContent = movieData.release_date.slice(0,4);
// Modify Runtime
let runtime = document.getElementById('runtime');
runtime.textContent = movieData.runtime;
// Modify Voter average
let voteAvg = document.getElementById('voteAvg');
voteAvg.textContent = (movieData.vote_average).toFixed(2);
// Modify Voter count
let voteCount = document.getElementById('voteCount');
voteCount.textContent = movieData.vote_count;
}
// Add genre badges to genre div on page with all Genres associated with movie
function displayGenres(movieGenreArray) {
// Get div element to hold genre badges
const genreDiv = document.getElementById('genres');
genreDiv.textContent = '';
// loop through each item in array and add genre element to div element
for (let i = 0; i < movieGenreArray.length; i++) {
let badge = document.createElement('span');
badge.classList.add('badge','text-bg-success','mx-1');
badge.textContent = movieGenreArray[i].name;
genreDiv.appendChild(badge);
}
}
// Filter the movies displayed when the particular genre button is clicked
async function filterByGenre(filterBtn) {
// Get the genre ID of the btn filter that was clicked
let genreId = parseInt(filterBtn.getAttribute('data-genreId'));
// Grab the movies Array from the database
let movies = await getMovies();
// Declare new array to put the filtered movies into
let filteredMovies = [];
// For movies that equal the genre id, put it into new movie array
for (let i = 0; i < movies.length; i++) {
// Get genres for movie
let movieGenreIds = movies[i].genre_ids;
// Add movie to new array if it has genre id
if ( movieGenreIds.includes(genreId) ) {
filteredMovies.push(movies[i]);
}
}
// Display movies based on new filtered array
displayMovies(filteredMovies);
}
TL;DR
In order to grab data with a 3rd-party API, use the fetch
method in a
try...catch statement
so that the app can gracefully inform the user of an issue if there is one trying to access the
data. This needs to go inside an
async function
with the await
keyword proceeding fetch
since
it takes awhile (comparatively)
to grab the data from the API and return it.
Code Explanation
Movie Garden was created with the following functions.
getMovies
grabs data about the most popular movies from "The Movide DB" (TMDB) using
their API
with the fetch
method in a try...catch statement. With the
try...catch statement
the app can gracefully inform the user of an issue if there is one trying to access the data
instead of just breaking. In this case it'll show a sweet alert. This needs to go
inside an
async function
with the await
keyword proceeding fetch
since it takes awhile (comparatively) to grab the data from the API and return it.
getMovie
is similar to getMovies
except instead of using the
API to get data for the most popular movies,
it uses the API to get detailed data for one movie. The one movie is identified with
the movieId
which is a parameter
for this function and used in the API call using string
interpolation.
displayMovies
shows the movies that are passed in as a parameter on the
page. This is done by first grabbing the HTML element the cards are to be placed in. A
template tag
is used on the elements of the card so the same structure can be used for each of the cards. This is
used in conjunction with a for loop to modify each element of the
card template for each movie and add it to the element the cards are to be placed in. The most
unique element that was modified is the button where a custom data-movieId
attribute
was set on each of the cards so that the Id of the movie could be accessed when the "More Info"
button is clicked.
displayAllMovies
uses getMovies
to grab the popular movie data from TMBD
and passes that data as an argument of displayMovies
.
showMovieDetails
puts the details of the movie into the modal when the
"More Info" button is clicked. The button that was clicked is a parameter of this function.
Using the custom data-movieId
attribute on the button, movieId is passed
as an argument to getMovie
.
The elements of the modal are then filled in the with data recieved back from the API
call.
displayGenres
takes in an array of genres for a specific movie as a
parameter. It then gets the element from the modal that is to hold the genre badges
to display all the genres associated with a particular movie.
filterByGenre
takes in a clicked filter button as a parameter. From that button, the
genreId is grabbed which is then used with the movies returned by getMovies
.
Using a for loop, each of the movies are checked to see if they have a genreId which
includes the genreId of the filter button that was clicked. If it does, the movie is placed
in a new array. This array is then passed as an argument to displayMovies
so that only
those movie cards are shown on the page.
What I learned
- There are functions that take awhile to run. These require the
await
keyword to be placed before it. If anawait
keyword is required it needs to be inside anasync function
. Theawait
keyword allows for the following function to finish doing its job before continuing with the rest of theasync function
. For example when used withfetch
to get data from an API. - Use a try...catch statement to control what happens if something goes wrong when
implementing
resources from 3rd-party sources. For example using
fetch
to access data from an API about movies. If an error happens, the catch block can be coded to present the user with information about what happened and next possible actions with a great UI experience. -
When trying to display similar elements on a page where only the content is changing, use
HTML
templates to easily recreate the elements and replace the content accordingly along
with
.content.cloneNode(true)
on the template element in the DOM.
Improvements
- Make sidebar sticky.
- Add also "Now Playing", "Top Rated", "Upcoming", "Trending" movie lists.
- A feature where a user can come to visit the page and their favorite movies can be saved to a list that is stored in the local storage.