This JavaScript code is designed to create a web application that allows you to compare movies. It uses an autocomplete feature to search for movies, fetches movie data from OMDb API, and displays a comparison of key movie statistics. This app is helpful for comparing different movies based on factors like awards, box office earnings, Metascore, IMDB rating, and IMDB votes.
You can integrate this movie comparison app into your movies/entertainment website, allowing users to make informed decisions on what to watch next.
How to Create Movie Comparison App in JavaScript
1. First of all, load the Normalize CSS by adding the following CDN link into the head tag of your HTML document.
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
2. After that, create the HTML structure for the movies comparison interface as follows:
<main> <header class="header"> <h1 class="header__title">Movie Comparison</h1> </header> <div class="columns"> <!-- Left side movie --> <section class="column"> <div id="left-autocomplete"></div> <div id="left-details"></div> </section> <!-- Right side movie --> <section class="column"> <div id="right-autocomplete"></div> <div id="right-details"></div> </section> </div> </main>
3. Now, use the following CSS code to style the app interface. You can modify the CSS rules according to your website/app design.
* { box-sizing: border-box; } p { margin: 0; } body { margin: 0; padding: 0; color: #fff; background-color: #1D253D; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } .columns { display: flex; max-width: 900px; margin: 0 auto; } .columns .column { flex: 0 0 50%; padding: 0 1rem; } .header { padding: 2rem 1rem; text-align: center; } .header__title { margin: 0; color: #6478B4; font-size: 20px; letter-spacing: 2px; } .autocomplete__label { display: block; } .autocomplete__input { display: block; width: 100%; margin-top: 0.5rem; padding: 1rem 1.25rem; border: 0; border-radius: 4px; color: #fff; background-color: #2d3a60; outline: 0; font-size: 18px; transition: all 0.15s ease-out; box-sizing: border-box; } .autocomplete__input:focus { box-shadow: 0 0 0 3px rgba(100, 120, 180, 0.75); } .autocomplete__input:hover { background-color: #364471; } .autocomplete .dropdown__menu__item img { width: 30px; margin-right: 1rem; } .dropdown { position: relative; vertical-align: top; display: inline-flex; width: 100%; } .dropdown--active .dropdown__menu { display: block; } .dropdown__menu { position: absolute; top: 100%; left: 0; z-index: 20; overflow-y: scroll; display: none; width: 100%; min-width: 12rem; max-height: 300px; padding: 0.5rem 0; border-radius: 4px; background-color: white; } .dropdown__menu__link { display: flex; align-items: center; padding: 0.5rem 1rem; color: #1D253D; cursor: pointer; transition: all 0.15s ease-out; } .dropdown__menu__link:hover, .dropdown__menu__link:focus { background-color: #eee; } .media { display: block; margin-bottom: 2rem; } .media__title { text-align: center; } .media__info { height: 175px; overflow-y: auto; } .media__figure { width: 100%; margin: 0; padding: 1rem; border-radius: 10px; background-color: #252f4e; } .media__figure img { display: block; margin: 0 auto; height: 200px; border-radius: 10px; } .compare { padding: 1.5rem 1rem; margin-bottom: 1rem; border-radius: 10px; color: #1D253D; } .compare--winner { background-color: #19CF7F; } .compare--loser { background-color: #F30C81; } .compare__title { margin-bottom: 0.5rem; font-weight: 700; font-size: 24px; } .compare--winner .compare__subtitle { color: #0e7447; } .compare--loser .compare__subtitle { color: #92074d; }
4. Load the Axios JS library by adding the following scripts before closing the body tag:
<script src='https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js'></script>
5. Finally, add the following JavaScript code between <script> tag (or external JS file) to enable comparison functionality.
/** If the calls fail, it might be because the api limit has been reached. It's able to do 1.000 calls/day, search for 89c28a6e and replace it with your own (you can get one for free at http://omdbapi.com/) */ // Some default classes and variables used in the app const DEFAULTS = { DROPDOWN_CLASS_ITEM: "dropdown__menu__item", DROPDOWN_CLASS_LINK: "dropdown__menu__link", DROPDOWN_CLASS_ACTIVE: "dropdown--active", COMPARE_CLASS_WINNER: "compare--winner", COMPARE_CLASS_LOSER: "compare--loser", API_BASE_URL: "https://www.omdbapi.com", API_KEY: "89c28a6e" }; // Reusable Autocomplete Class class Autocomplete { constructor(config) { ({ root: this.root, optionTemplate: this.optionTemplate, onOptionSelect: this.onOptionSelect, inputValue: this.inputValue, fetchData: this.fetchData } = config); this.createRootTemplate(this.root); this.input = this.root.querySelector(".autocomplete__input"); this.dropdown = this.root.querySelector(".autocomplete__dropdown"); this.resultsWrapper = this.root.querySelector(".results"); this.initListeners(); } initListeners() { this.input.addEventListener("input", this.debounce(ev => this.onInput(ev), 500)); document.addEventListener("click", ev => { if (!this.root.contains(ev.target)) { this.dropdown.classList.remove(DEFAULTS.DROPDOWN_CLASS_ACTIVE); } }); } async onInput(ev) { const items = await this.fetchData(ev[0].target.value); if (!items.length) { this.dropdown.classList.remove(DEFAULTS.DROPDOWN_CLASS_ACTIVE); return; } this.resultsWrapper.innerHTML = ""; this.dropdown.classList.add(DEFAULTS.DROPDOWN_CLASS_ACTIVE); for (const item of items) { const option = document.createElement("li"); option.classList.add(DEFAULTS.DROPDOWN_CLASS_ITEM); const link = document.createElement("a"); link.classList.add(DEFAULTS.DROPDOWN_CLASS_LINK); link.innerHTML = this.optionTemplate(item); option.appendChild(link); option.addEventListener("click", () => { this.dropdown.classList.remove(DEFAULTS.DROPDOWN_CLASS_ACTIVE); this.input.value = this.inputValue(item); this.onOptionSelect(item); }); this.resultsWrapper.appendChild(option); } } debounce(callback, delay = 1000) { return (...args) => { if (this.timeoutId) clearTimeout(this.timeoutId); this.timeoutId = setTimeout(() => { callback.call(null, args); }, delay); }; } createRootTemplate(el) { el.innerHTML = ` <div class="autocomplete"> <label class="autocomplete__label"> Search <input class="autocomplete__input" /> </label> <div class="autocomplete__dropdown dropdown"> <ul class="dropdown__menu results"> </ul> </div> </div> `; } } // Class to compare movies class MovieComparison { constructor() { this.init(); } movieAutocompleteConfig() { return { optionTemplate(movie) { const imgSrc = movie.Poster === "N/A" ? "" : movie.Poster; return ` <img src="${imgSrc}" /> ${movie.Title} (${movie.Year}) `; }, inputValue(movie) { return movie.Title; }, async fetchData(searchTerm) { const response = await axios.get(DEFAULTS.API_BASE_URL, { params: { apikey: DEFAULTS.API_KEY, // This api can only be used 1000 times a day s: searchTerm } }); return response.data.Error ? [] : response.data.Search; } }; } init() { new Autocomplete({ ...this.movieAutocompleteConfig(), root: document.querySelector("#left-autocomplete"), onOptionSelect: movie => { this.onMovieSelect( movie, document.querySelector("#left-details"), "left" ); } }); new Autocomplete({ ...this.movieAutocompleteConfig(), root: document.querySelector("#right-autocomplete"), onOptionSelect: movie => { this.onMovieSelect( movie, document.querySelector("#right-details"), "right" ); } }); } async onMovieSelect(movie, summaryElement, side) { const response = await axios.get(DEFAULTS.API_BASE_URL, { params: { apikey: DEFAULTS.API_KEY, i: movie.imdbID } }); summaryElement.innerHTML = this.movieTemplate(response.data); if (side === "left") { this.leftMovie = response.data; } else { this.rightMovie = response.data; } if (this.leftMovie && this.rightMovie) { this.runComparison(); } } runComparison() { const leftSideStats = document.querySelectorAll("#left-details .compare"); const rightSideStats = document.querySelectorAll("#right-details .compare"); console.log(rightSideStats); for (const [i, leftStat] of leftSideStats.entries()) { const rightStat = rightSideStats[i]; const leftSideValue = parseInt(leftStat.dataset.value); const rightStatValue = parseInt(rightStat.dataset.value); if (rightStatValue > leftSideValue) { leftStat.classList.remove(DEFAULTS.COMPARE_CLASS_WINNER); leftStat.classList.add(DEFAULTS.COMPARE_CLASS_LOSER); } else { rightStat.classList.remove(DEFAULTS.COMPARE_CLASS_WINNER); rightStat.classList.add(DEFAULTS.COMPARE_CLASS_LOSER); } } } movieTemplate(detail) { const boxOffice = parseInt( detail.BoxOffice.replace(/\$/g, "").replace(/,/g, "") ); const metascore = parseInt(detail.Metascore); const imdbScore = parseFloat(detail.imdbRating); const imdbVotes = parseInt(detail.imdbVotes.replace(/,/g, "")); const awardsCount = detail.Awards.split(" ") .filter(Number) .reduce((acc, cur) => acc + parseInt(cur), 0); return ` <article class="media"> <h1 class="media__title">${detail.Title}</h1> <figure class="media__figure"> <img src="${detail.Poster}" /> </figure> <div class="media__info"> <h4>${detail.Genre}</h4> <p>${detail.Plot}</p> </div> </article> <article class="compare ${DEFAULTS.COMPARE_CLASS_WINNER}" data-value="${awardsCount}"> <p class="compare__title">${detail.Awards}</p> <p class="compare__subtitle">Awards</p> </article> <article class="compare ${DEFAULTS.COMPARE_CLASS_WINNER}" data-value="${boxOffice}"> <p class="compare__title">${detail.BoxOffice}</p> <p class="compare__subtitle">Box Office</p> </article> <article class="compare ${DEFAULTS.COMPARE_CLASS_WINNER}" data-value="${metascore}"> <p class="compare__title">${detail.Metascore}</p> <p class="compare__subtitle">Metascore</p> </article> <article class="compare ${DEFAULTS.COMPARE_CLASS_WINNER}"" data-value="${imdbScore}"> <p class="compare__title">${detail.imdbRating}</p> <p class="compare__subtitle">IMDB Rating</p> </article> <article class="compare ${DEFAULTS.COMPARE_CLASS_WINNER}"" data-value="${imdbVotes}"> <p class="compare__title">${detail.imdbVotes}</p> <p class="compare__subtitle">IMDB Votes</p> </article> `; } } const comparison = new MovieComparison();
If you plan to use the app regularly, you can get your API key from OMDb API for an improved experience. Replace the default API key in the code with your own.
That’s all! hopefully, you have successfully created a Movie Comparison App in JavaScript. If you have any questions or suggestions, feel free to comment below.
Similar Code Snippets:
I code and create web elements for amazing people around the world. I like work with new people. New people new Experiences.
I truly enjoy what I’m doing, which makes me more passionate about web development and coding. I am always ready to do challenging tasks whether it is about creating a custom CMS from scratch or customizing an existing system.