I have been working on this problem for a couple of days… SO what I want to happen, is that when I search for a movie to add to the watchlist… if it’s a movie that I have already added, I want to:
-
find the div that is holding that objects data
-
get the first child and add a class of hidden
-
then get the second child and remove the class that’s hidden
The result should be that any movie that has already been added to the watchlist should have the “added” icon indicator displayed instead of the add to watchlist button div.
I’m not even sure if this is the correct way to go about this but here is what I have tried in index.js so far:
const formEl = document.getElementById("form-el");
const moviesHolder = document.getElementById("movies-holder");
// localStorage.clear();
let movieDescription = "";
let addIconDiv = "";
let watchlistArray = JSON.parse(localStorage.getItem("imdbMovie")) || [];
formEl.addEventListener("submit", (e) => {
const searchFieldValue = document.getElementById("search-field").value;
const searchNotFoundHolder = document.getElementById(
"search-not-found-holder"
);
const searchNotFoundText = document.getElementById("search-not-found-text");
const introPrompt = document.getElementById("intro-prompt");
const mainHolder = document.getElementById("main-holder");
movieDescription = "";
let imdbMovieIdArray = [];
e.preventDefault();
fetch(
`http://www.omdbapi.com/?apikey=my_api_key&s=${searchFieldValue}&type=movie`
)
.then((res) => res.json())
.then((movieData) => {
document.getElementById("search-field").value;
introPrompt.classList.add("hidden");
mainHolder.classList.remove("vertical-height");
if (movieData.Search === undefined) {
moviesHolder.innerHTML = "";
searchNotFoundHolder.classList.add("search-not-fount-vertical-height");
searchNotFoundText.classList.remove("hidden");
searchNotFoundText.textContent =
"Unable to find what you’re looking for. Please try another search.";
} else {
searchNotFoundHolder.classList.remove(
"search-not-fount-vertical-height"
);
searchNotFoundHolder.classList.add("hidden");
searchNotFoundText.classList.add("hidden");
for (let movie of movieData.Search) {
imdbMovieIdArray.push(movie.imdbID);
}
}
})
.then(() => {
for (let imdbMovieId of imdbMovieIdArray) {
fetch(
`http://www.omdbapi.com/?apikey=my_api_key&i=${imdbMovieId}&type=movie&plot=full`
)
.then((res) => res.json())
.then((imdbMovieData) => {
// console.log(imdbMovieData);
document.addEventListener("click", (e) => {
if (e.target.dataset.addToWatchlist) {
handleWatchlistItem(
e.target.dataset.addToWatchlist,
imdbMovieData
);
}
});
movieDescription += `
<div class="movie-card-holder">
<img src="${
imdbMovieData.Poster === "N/A"
? "/images/movie-jacket-sub.png"
: imdbMovieData.Poster
}" class="movie-poster">
<div class="movie-content-holder">
<div class="movie-and-rating-holder">
<h2 class="movie-title">${imdbMovieData.Title}
<span class="movie-rating"><span class="star-emoji">⭐️</span>${
imdbMovieData.imdbRating === "N/A"
? "no rating"
: imdbMovieData.imdbRating
}</span></h2>
</div>
<div class="time-and-genre-holder">
<div class="time-and-genre-container">
<p class="movie-time">${
imdbMovieData.Runtime === "N/A"
? ""
: imdbMovieData.Runtime
}</p>
<p class="movie-genre">${
imdbMovieData.Genre === "N/A" ? "" : imdbMovieData.Genre
}</p>
</div>
<div class="add-to-watchlist-btn-holder">
<button class="add-to-watchlist-btn" data-add-to-watchlist=${
imdbMovieData.imdbID
}>Watchlist</button>
<div class="added-icon hidden">
Added
</div>
</div>
</div>
<div class="plot-holder">
<p>${
imdbMovieData.Plot === "N/A"
? "<span class='no-description'>Plot not available.</span>"
: handlePlot(imdbMovieData)
}</p>
</div>
</div>
</div>
`;
// Working here //////////////////////////////////////////////////////////////////////////////
// if there's a match between an id in the watchlist array and an id of one of the objects
// the search targets the movies in the watchlist array finds the add to watchlist watchlist
// button for that movie and applies a class of hidden. Then it finds the added icon dive
// and removes the class of hidden
for (let watchlistItem of watchlistArray) {
if (watchlistItem.imdbID === imdbMovieData.imdbID) {
const addToWatchlistBtnHolder = document.querySelectorAll(
".add-to-watchlist-btn-holder"
);
for (let addToWatchlistBtn of addToWatchlistBtnHolder) {
addToWatchlistBtn.children[0].classList.add("hidden");
}
}
}
// //////////////////////////////////////////////////////////////////////////////////////////
function handleWatchlistItem(watchlistItemID, imdbMovieData) {
const addToWatchlistBtns = document.querySelectorAll(
".add-to-watchlist-btn"
);
for (let addToWatchlistBtn of addToWatchlistBtns) {
const watchlistBtn = addToWatchlistBtn.dataset.addToWatchlist;
if (watchlistBtn === watchlistItemID) {
addToWatchlistBtn.classList.add("hidden");
addToWatchlistBtn.nextElementSibling.classList.remove(
"hidden"
);
}
}
if (imdbMovieData.imdbID === watchlistItemID) {
let watchlistMovie = imdbMovieData;
watchlistArray.push(watchlistMovie);
// console.log(watchlistArray);
localStorage.setItem(
"imdbMovie",
JSON.stringify(watchlistArray)
);
}
}
moviesHolder.innerHTML = movieDescription;
});
}
});
formEl.reset();
});
function handlePlot(fullString) {
document.addEventListener("click", (e) => {
if (e.target.dataset.readMore) {
handleReadMore(e.target.dataset.readMore, e);
} else if (e.target.dataset.readLess) {
handleReadLess(e.target.dataset.readLess, e);
}
});
let fullPlot = fullString.Plot;
let shortPlot =
fullPlot.split(/\s+/).slice(0, 22).join(" ") +
`...<button class='read-more-btn' data-read-more=${fullString.imdbID}>Read More</button>`;
if (fullPlot > fullPlot.split(/\s+/).slice(0, 22).join(" ")) {
return shortPlot;
} else {
return fullPlot;
}
function handleReadMore(movieID, e) {
if (movieID === fullString.imdbID) {
e.target.parentNode.innerHTML =
fullPlot +
`<button class='read-more-btn' data-read-less=${fullString.imdbID}>Read Less</button>`;
}
}
function handleReadLess(movieID, e) {
if (movieID === fullString.imdbID) {
e.target.parentNode.innerHTML = shortPlot;
}
}
}
Here is my index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700;800&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="index.css" />
<script src="index.js" type="module" defer></script>
<title>Brad Cole's Watchlist</title>
</head>
<body>
<div class="site-container">
<header>
<h1>Find Your Film</h1>
<a href="./watchlist.html" class="watchlist-btn">My Watchlist</a>
<form id="form-el" class="search-form">
<input
type="search"
name="search-field"
class="search-field"
id="search-field"
/>
<button class="search-btn">Search</button>
</form>
</header>
<main id="main-holder" class="vertical-height">
<div id="search-not-found-holder">
<p id="search-not-found-text"></p>
</div>
<div class="intro-prompt" id="intro-prompt">
<img
class="film-icon"
src="./images/film-icon.svg"
alt="icon of a clipped film strip"
/>
<h2 class="intro-text">Start Exploring</h2>
</div>
<div id="movies-holder"></div>
</main>
</div>
</body>
</html>
Here is my CSS:
:root {
/* Font Colors */
--white: #fff;
--light-mid-grey: #a5a5a5;
--dark-mid-grey: #9ca3af;
--dark-grey: #787878;
--very-dark-grey: #2e2e2f;
}
/* Josh Comeau CSS Reset */
*,
*::before,
*::after {
box-sizing: border-box;
}
* {
margin: 0;
}
body {
-webkit-font-smoothing: antialiased;
}
img,
svg {
display: block;
max-width: 100%;
}
input,
button {
font: inherit;
}
/* Typography */
body {
font-family: "Inter", sans-serif;
}
header > h1 {
font-weight: 800;
font-size: 2.675rem;
color: var(--white);
}
.watchlist-btn {
color: var(--white);
font-weight: 700;
font-size: 0.875rem;
}
.intro-text {
font-size: 1.125rem;
color: var(--very-dark-grey);
}
#search-not-found-text {
font-size: 1.125rem;
color: var(--dark-grey);
font-weight: 700;
text-align: center;
line-height: 20px;
}
.search-btn {
font-weight: 400;
font-size: 0.875rem;
color: var(--white);
line-height: 20px;
}
input {
font-family: "Inter", sans-serif;
font-size: 0.875rem;
font-weight: 400;
color: var(--light-mid-grey);
letter-spacing: 0.0156em;
line-height: 20px;
}
.movie-title {
font-size: 1.125rem;
font-weight: 500;
color: var(--white);
}
.movie-rating,
.movie-time {
color: var(--white);
font-size: 0.75rem;
white-space: nowrap;
}
.movie-genre {
color: var(--white);
font-size: 0.75rem;
}
.plot-holder > p {
font-size: 0.875rem;
color: var(--light-mid-grey);
font-weight: 400;
line-height: 20px;
}
.no-description {
font-size: 0.75rem;
color: #d6ffdf;
}
.watchlist-text {
color: var(--dark-grey);
font-size: 1.125rem;
font-weight: 700;
}
/* Layout & Related Styling */
.vertical-height {
height: calc(100vh - 12.5em);
}
.search-not-fount-vertical-height {
height: calc(100vh - 14.5em);
}
html {
height: 100%;
}
body {
background-color: #1c1c1c;
}
header {
position: relative;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
object-fit: cover;
background-image: url("/images/office-movie-posters-img.png");
background-repeat: no-repeat;
background-position: center;
box-shadow: inset 0 0 0 1000px rgba(15, 10, 10, 0.7);
height: 200px;
text-align: center;
max-width: 550px;
margin: 0 auto;
padding: 0;
}
#search-not-found-holder {
display: flex;
width: 321px;
justify-content: center;
align-items: center;
}
.film-icon {
width: 70px;
margin-bottom: 0.75em;
align-self: center;
}
main {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #121212;
max-width: 550px;
margin: 0 auto;
padding: 0 1.5em;
}
.intro-prompt {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex-grow: 1;
}
.hidden {
display: none;
}
#movies-holder {
display: flex;
max-width: 550px;
width: 100%;
flex-direction: column;
margin-top: 2em;
}
.movie-card-holder {
display: flex;
padding-bottom: 1.537em;
border-bottom: 1px solid #2c2c2c;
width: 100%;
}
img {
padding-top: 1.625em;
display: block;
align-self: start;
}
.movie-poster {
width: 6.188em;
margin-right: 1.313em;
}
.movie-content-holder {
width: 100%;
display: flex;
flex-direction: column;
}
.movie-and-rating-holder {
display: flex;
align-items: center;
width: 100%;
margin-top: 2em;
}
.movie-rating {
margin-left: 0.5em;
}
.star-emoji {
margin-right: 0.75em;
}
.time-and-genre-holder {
display: flex;
margin-top: 0.75em;
flex-direction: column;
height: 1.75em;
}
.time-and-genre-container {
display: flex;
flex-direction: row;
}
.movie-time {
margin-right: 1.125em;
}
.plot-holder {
margin-top: 0.625em;
}
.watchlist-text {
margin-bottom: 0.938em;
}
.added-icon {
font-size: 0.75rem;
color: #ffe209;
background-image: url(./images/added-icon-hvr.svg);
background-repeat: no-repeat;
padding-left: 1.75em;
background-size: contain;
align-self: center;
}
.add-to-watchlist-btn-holder {
display: flex;
}
/* Input, buttons, a, etc.. */
.watchlist-btn {
background: none;
border: none;
cursor: pointer;
margin-top: 1em;
text-decoration: none;
}
.watchlist-btn:hover {
color: #ffe209;
}
.add-to-watchlist-btn {
background: none;
border: none;
color: var(--white);
background-image: url(./images/add-to-watchlist-icon.svg);
background-repeat: no-repeat;
background-position: left 0 top 1px;
background-size: 16px;
padding-left: 1.75em;
font-size: 0.75rem;
cursor: pointer;
margin-top: 1em;
}
.add-to-watchlist-btn:hover {
color: #ffe209;
background-image: url(./images/add-to-watchlist-icon-hvr.svg);
}
.search-form {
position: absolute;
bottom: -1.125em;
display: flex;
width: 85%;
max-width: 462px;
}
.search-field {
background-color: var(--very-dark-grey);
border: none;
padding: 0.563em 0.813em 0.563em 2.75em;
border-radius: 6px 0 0 6px;
width: 100%;
background-image: url("./images/search-icon.svg");
background-repeat: no-repeat;
background-size: 20px;
background-position: left 0.813em top 50%;
}
.search-btn {
background-color: #4b4b4b;
border: none;
border-radius: 0 6px 6px 0;
padding: 0.563em 0.688em 0.563em 1.063em;
cursor: pointer;
width: 120px;
}
input:focus {
outline: none;
}
.read-more-btn {
font-size: 0.75rem;
background: none;
border: none;
color: var(--white);
cursor: pointer;
}
.read-more-btn:hover {
color: #ffe209;
}
.find-movies-btn {
color: var(--white);
text-decoration: none;
margin: 0 auto;
display: block;
font-size: 0.875rem;
font-weight: 700;
background: url(./images/add-to-watchlist-icon.svg);
background-repeat: no-repeat;
width: 200px;
padding-left: 25px;
}
.find-movies-btn:hover {
color: #ffe209;
background: url(./images/add-to-watchlist-icon-hvr.svg);
background-repeat: no-repeat;
padding: 0;
width: 200px;
padding-left: 25px;
}
@media (min-width: 700px) {
header {
flex-direction: row;
justify-content: space-between;
padding: 0 2.625em;
}
.time-and-genre-holder {
flex-direction: row;
align-items: center;
flex-wrap: wrap;
}
.time-and-genre-container {
margin-top: 0.063em;
}
.movie-genre {
white-space: nowrap;
margin-right: 1.75em;
}
.add-to-watchlist-btn {
margin-top: 0;
}
}
I also have watchlist.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700;800&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="index.css" />
<title>Brad Cole's Watchlist</title>
</head>
<body>
<div class="site-container">
<header>
<h1>My Watchlist</h1>
<a href="./index.html" class="watchlist-btn">Search for movies</a>
</header>
<main id="main-holder" class="vertical-height">
<div id="watchlist-holder"></div>
</main>
</div>
<script src="watchlist.js" type="module"></script>
</body>
</html>
and I have watchlist.js:
const watchlistText = document.getElementById("watchlist-text");
const watchlistHolder = document.getElementById("watchlist-holder");
let output = ``;
let movieItem = JSON.parse(localStorage.getItem("imdbMovie"));
if (movieItem) {
for (let movie of movieItem) {
output += `
<h1>${movie.Title}</h1>
`;
}
watchlistHolder.innerHTML = output;
} else {
watchlistHolder.innerHTML = `
<p class="watchlist-text" id="watchlist-text">Your watchlist is looking a little empty...</p>
<a href="./index.html" class="find-movies-btn">Let's add some movies!</a>
`;
}
I know this is a lot of code but if anyone can help out it would be an absolute God send!
Keeping my fingers crossed!