how to display the right movie informations in an overlay? - javascript

I'm looking for solutions to display the right movie information in my overlay.
I have a "popup window" that appears when i click on a movie and it is supposed to display movie's informations in it but when I click on a movie, no matter which one it is, it only displays the last movie informations, what Should I do to fix it ?
const movieIntegration =() => {
allMovies.map(movie=> {
movieGallery.innerHTML += `<div class="imgContainer">
<img src="${movie.img}" alt="${movie.name}">
<div class="titleContainer">
<div class="movieTitle"> ${movie.name} </div>
<div class="seemore"> See more </div>
</div>
</div>`
const seemore = document.querySelectorAll(".seemore")
seemore.forEach(elm => {
elm.addEventListener("click",() => {
pageContainer.innerHTML += `<div class="popupContainer">
<div class="popup">
${movie.name}
<div id="likeButton">
<img src="img/like.png">
</div>
<div id="editButton">
<img src="img/edit.png">
</div>
<a href="submit.html">
<div id="addingButton">
<img src="img/add.png">
</div>
</a>
</div>
</div>`
console.log(true)
}, true)
})
})
}

the problem is that you are getting all the .seemore element for each movie and you are editing the content of ALL elements for each movie, so the last movie will overwrite the content for all the previous.
A solution could be something like this:
const movieIntegration = () => {
allMovies.map((movie) => {
movieGallery.innerHTML += `<div class="imgContainer">
<img src="${movie.img}" alt="${movie.name}">
<div class="titleContainer">
<div class="movieTitle"> ${movie.name} </div>
<div class="seemore"> See more </div>
</div>
</div>`
})
const seemore = document.querySelectorAll('.seemore')
seemore.forEach((elm, i) => {
elm.addEventListener(
'click',
() => {
pageContainer.innerHTML += `<div class="popupContainer">
<div class="popup">
${allMovies[i].name}
<div id="likeButton">
<img src="img/like.png">
</div>
<div id="editButton">
<img src="img/edit.png">
</div>
<a href="submit.html">
<div id="addingButton">
<img src="img/add.png">
</div>
</a>
</div>
</div>`
},
true
)
})
}
In this way you are mapping the .seemore elements AFTER you finish the map of allMovies and, for each .seemore element you get the associated movie and write his name inside.

Related

Why my call map function is hide in the count nodeList but it is visible in return output?

This will be a complex sample cause my codes is like a lot...
So basically I just direct to my point. My problem is that I don't know why my list map function is not includes the output function of return when I'm trying to get the document.querySelectorAll() of all the items. Basically something like this.
<div className='gallery' style={ ispost ? { display:'none' } : {display:"block"}}>
{mainList.map((elem,idx) => {
return (
<div className="gallery-container" key={idx}>
<div className="l">
<div className="l-box">
<div className="text">
<div className="hide">
<h2> Onigsahima Tokyo </h2>
</div>
</div>
<div className="hide">
<div className="color-sample">
<img src={g3} alt="" />
</div>
</div>
</div>
</div>
<div className="r">
<div className="r-box">
<div className="hide">
<div className="color-sample">
<img src={g3} alt="" />
</div>
</div>
</div>
<div className="r-box">
<div className="hide">
<div className="color-sample">
<img src={g3} alt="" />
</div>
</div>
</div>
<div className="r-box">
<div className="hide">
<div className="color-sample">
<img src={g3} alt="" />
</div>
</div>
</div>
<div className="r-box">
<div className="hide">
<div className="color-sample">
<img src={g3} alt="" />
</div>
</div>
</div>
</div>
</div>
)
})}
<div className="gallery-container" style={ ispost ? { display:'none' } : {display:"inline-grid"}}>
<div className="l">
<div className="l-box">
<div className="text">
<div className="hide">
<h2> Onigsahima Tokyo </h2>
</div>
</div>
<div className="hide">
<div className="color-sample">
<img src={g3} alt="" />
</div>
</div>
</div>
</div>
<div className="r">
<div className="r-box">
<div className="hide">
<div className="color-sample">
<img src={g3} alt="" />
</div>
</div>
</div>
<div className="r-box">
<div className="hide">
<div className="color-sample">
<img src={g3} alt="" />
</div>
</div>
</div>
<div className="r-box">
<div className="hide">
<div className="color-sample">
<img src={g3} alt="" />
</div>
</div>
</div>
<div className="r-box">
<div className="hide">
<div className="color-sample">
<img src={g3} alt="" />
</div>
</div>
</div>
</div>
</div>
</div>
And then I have a useEffect() and I'll show all the codes about it..but don't get confused about it just focus on the querySelectorAll() cause it is the only thing that affect it all the animation
useEffect(() => {
gsap.registerPlugin(ScrollTrigger,CSSRulePlugin)
// gsap.registerPlugin(CSSRulePlugin)
const sections_ = document.querySelectorAll('.gallery-container')
console.log(sections_)
let sections = gsap.utils.toArray(".gallery-container")
console.log(sections)
let scrollTween = gsap.to(sections, {
xPercent: -100 * (sections.length - 1),
ease: "none", // <-- IMPORTANT!
scrollTrigger: {
trigger: ".gallery",
pin: true,
scrub: 3,
end: "+=3000",
// markers:true
}
});
gsap.to(".gallery-container:nth-child(1) .color-sample",{
y:0,
ease:"none",
scrollTrigger:{
trigger:".gallery-container:nth-child(1)",
containerAnimation:scrollTween,
start:"0% 0%",
end:"10% 6%",
// markers:{startColor: "orange", endColor: "green"},
scrub:2,
}
})
const rule = CSSRulePlugin.getRule(`.r-box:after`)
const rule2 = CSSRulePlugin.getRule(`.r-box:before`)
gsap.to([rule,rule2],{
width:'35%',
height:'35%',
background:"yellow",
delay:3,
ease:"none",
scrollTrigger:{
trigger:`.gallery-container:nth-child(1)`,
containerAnimation:scrollTween,
start:"0% 0%",
end:"10% 6%",
// markers:true,
scrub:2,
}
})
gsap.to(`.gallery-container:nth-child(1) .text h2`,{
y:0,
// delay:2,
ease:"none",
scrollTrigger:{
trigger:`.gallery-container:nth-child(1)`,
containerAnimation:scrollTween,
start:"0% 0%",
end:"10% 6%",
// markers:true,
scrub:2,
}
})
sections.forEach((elem,i) => {
gsap.to(`.gallery-container:nth-child(${i+2}) .color-sample`,{
y:0,
ease:"none",
scrollTrigger:{
trigger:`.gallery-container:nth-child(${i+2})`,
containerAnimation:scrollTween,
start:"center 50%",
end:"center 60%",
// markers:true,
scrub:2,
}
})
gsap.to(`.gallery-container:nth-child(${i+2}) .text h2`,{
y:0,
// delay:2,
ease:"none",
scrollTrigger:{
trigger:`.gallery-container:nth-child(${i+2})`,
containerAnimation:scrollTween,
start:"center 50%",
end:"center 60%",
// markers:true,
scrub:2,
}
})
const rule = CSSRulePlugin.getRule(`.r-box:after`)
const rule2 = CSSRulePlugin.getRule(`.r-box:before`)
gsap.to([rule,rule2],{
width:'35%',
height:'35%',
background:"yellow",
delay:3,
ease:"none",
scrollTrigger:{
trigger:`.gallery-container:nth-child(${i+2})`,
containerAnimation:scrollTween,
start:"center 50%",
end:"center 60%",
// markers:true,
scrub:2,
}
})
})
const arrowsColor = document.querySelectorAll('.arrow.first ion-icon')
const arrows2Color = document.querySelectorAll('.arrow.second ion-icon')
var scrollPos = 0
window.addEventListener('scroll',() => {
if ((document.body.getBoundingClientRect()).top > scrollPos) {
// console.log('Right')
arrowsColor.forEach(elem => {
elem.style.color = 'black'
})
arrows2Color.forEach(elem => {
elem.style.color = 'yellow'
})
} else {
// console.log('Left')
arrowsColor.forEach(elem => {
elem.style.color = 'yellow'
})
arrows2Color.forEach(elem => {
elem.style.color = 'black'
})
}
scrollPos = (document.body.getBoundingClientRect()).top
})
},[])
I don't know if this is easiest way to explain it but this is the best I can..
Note that mainList is a useState so I'll have something like this in my codes
when I am pushing the items in setMainList
useEffect(() => {
axios.get('http://localhost:7777/gallery')
.then(res => {
let del = []
res.data.map((elem,i) => {
console.log(i)
setMainList([...mainList,elem])
})
})
},[])
Yes it works but why the document.querySelectorAll don't detect if there is a new element that I pop in that mainList.map function? I don't understand why..It shouldn't be this kind of way. I always do this but never encounter this bug..
Note that mainList.map() is like visible but it is not include in that querySelectorlAll
Please help badly need it to get this thing done.
Because your useEffect callback runs only once since you haven't added any dependencies. If you want the callback to be invoked whenever mainList changes, add mainList to the useEffect dependency list like so
useEffect(() => {
//...
}, [mainList])
Be careful though! You should use the return callback to remove any listeners or subscriptions you've set up.
useEffect(() => {
//...
function onScroll() {
//...
}
window.addEventListener('scroll', onScroll)
return () => {
// remove listeners
window.removeEventListener('scroll', onScroll)
}
}, [mainList])
I don't know how gsap works, but you might also want to "deregister" the plugin in the tear-down callback, or just use a different useEffect callback with no dependencies to register it only once - you probably still want to "deregister" it either way, but you wont do it every time mainList changes.
Edit: I highly suggest you read the useEffect docs
Edit2: Here's a gist

How can I use jQuery line by line

I want to display comments line by line in a div but the div is closing first and after that the comments are listing.
if (comments.num_replies > 0) {
$("#showComment").append(`<div id="replyContainer${comments.comment_id}" class="replyContainer">`);
comments.comment_replies.forEach((replies) => {
$("#showComment").append(`
<div class="img-comment reply">
<img src="${home_url}img/user.png">
<div class="m-2 p-3 ">
<div class="user-date"><p class="username">#${replies.replier_username}</p><p class="date">${replies.dates}</p></div>
<p class="comment_content">${replies.reply_comment_content.replace(/\n/g, "<br>")}</p>
</div>
</div>
`)
});
$("#showComment").append(`</div>`);
}
You can try something like this
if (comments.num_replies > 0) {
let replies = comments.comment_replies.map((replies) => (
`<div class="img-comment reply">
<img src="${home_url}img/user.png">
<div class="m-2 p-3 ">
<div class="user-date"><p class="username">#${replies.replier_username}</p><p class="date">${replies.dates}</p></div>
<p class="comment_content">${replies.reply_comment_content.replace(/\n/g, "<br>")}</p>
</div>
</div>`
));
$("#showComment").append(`<div id="replyContainer${comments.comment_id}" class="replyContainer">${replies.join('')}</div>`);
}

I need to move a node list from one parent to another

I'm trying to move a node list (in my case img HTML tags with a class name of ".images") when I reach a specific breakpoint to another parent as the first child of that new parent.
/* BEFORE BREAKPOINT */
<div class="old-parent">
<img class="images">
<div class="new-parent">
</div>
</div>
<div class="old-parent">
<img class="images">
<div class="new-parent">
</div>
</div>
<div class="old-parent">
<img class="images">
<div class="new-parent">
</div>
</div>
/*AFTER REACHING THE BREAKPOINT*/
<div class="old-parent">
<div class="new-parent">
<img class="images">
</div>
</div>
<div class="old-parent">
<div class="new-parent">
<img class="images">
</div>
</div>
<div class="old-parent">
<div class="new-parent">
<img class="images">
</div>
</div>
So far is working when I use a single selector, however when I try to select them all and transfer them to a new parent is not working.
const newParent = document.querySelectorAll('.new-parent');
const images = document.querySelectorAll('.images');
const mediaQ = window.matchMedia('(max-width: 494px)');
const changeImg = (e) => {
if (e.matches) {
newParent.forEach(elem => {
elem.insertBefore(images, elem.childNodes[0]);
})
}
};
mediaQ.addEventListener('change', changeImg);
Then returns an error in the console:
Uncaught TypeError: Failed to execute 'insertBefore' on 'Node': parameter 1 is not of type 'Node'
You need to index images to move one image at a time.
const changeImg = (e, i) => {
if (e.matches) {
newParent.forEach(elem => {
elem.insertBefore(images[i], elem.childNodes[0]);
})
}
};

How to check if all the input values are equal to my data?

I have 32 items in my array, all of them have these properties: id, word, image. User has to guess what's in all the images and write their guess in inputs (so 32 inputs in total). I need to check if the input equals my arrays property "word" and then when clicked a button (type submit, all my pic's and inputs are in a form) display some text for example "Oops! Guess again" if wrong and "Yay! You got it correctly" if right. The text should appear below every input. I displayed all the pictures and inputs with a forEach, and i'm using bulma framework for this page:
const wordBox = info.forEach((words) => {
mainColumns.innerHTML += `
<div class="column is-one-quarter">
<div class="card">
<div class="card-image">
<figure class="image is-4by3">
<img src=${words.image} alt="Placeholder image">
</figure>
</div>
<div class="card-content">
<div class="media">
<div class="media-content">
<input class="input" id="text" type="text" placeholder="Įvesk žodį">
</div>
</div>
<div class="content">
Content
</div>
</div>
</div>
</div>`;
});
Any ideas?
This is how it should look like (the result should appear in content place)
Something like this
I use change instead of a button click
const info = [
{word:"flower",image:"flower.gif"},
{word:"boat",image:"boat.gif"}
];
const mainColumns = document.getElementById("mainColumns");
mainColumns.innerHTML = info.map(({image,word}) =>
`<div class="column is-one-quarter">
<div class="card">
<div class="card-image">
<figure class="image is-4by3">
<img src=${image} alt="Placeholder image">
</figure>
</div>
<div class="card-content">
<div class="media">
<div class="media-content">
<input class="input" data-word="${word}" type="text" placeholder="Įvesk žodį">
<span class="correct hide">Yay</span>
<span class="wrong hide">NOO</span>
</div>
</div>
<div class="content">
Content
</div>
</div>
</div>
</div>`).join("");
mainColumns.addEventListener("change",function(e) {
const correct = [...mainColumns.querySelectorAll("[data-word]")].map(input => {
if (input.value) {
const correct = input.value === input.dataset.word;
parent = input.closest("div");
parent.querySelector(".correct").classList.toggle("hide",!correct)
parent.querySelector(".wrong").classList.toggle("hide",correct);
return correct ? 1 : 0;
}
else return 0;
}).reduce((a,b)=>a+b);
document.getElementById("correct").innerText = correct;
})
#mainColumns { display:flex; }
.hide { display: none; }
<div id="mainColumns"></div>
Correct: <span id="correct"></span>
What you can do is to filter the word array with word from the input value. Then check if the length is equal zero, No match, if the length is greater than one, then there is a match.
const status = wordBox.filter(item => item.word === inputWord)
I'd move towards keeping the objects and the HTML separate, binding the HTML to the object and vice versa. This means including a couple more properties to your array elements.
let info = [{
image: 'flower.png',
word: 'flower',
content: '',
guess: ''
}];
function bindWords() {
info.forEach((words) => {
mainColumns.innerHTML = `
<div class="column is-one-quarter">
<div class="card">
<div class="card-image">
<figure class="image is-4by3">
<img src=${words.image} alt="Placeholder image">
</figure>
</div>
<div class="card-content">
<div class="media">
<div class="media-content">
<input class="input" data-word="${words.word}" type="text" placeholder="Įvesk žodį" value="${words.guess}">
</div>
</div>
<div class="content">
${words.content}
</div>
</div>
</div>
</div>`;
});
}
bindWords();
check.addEventListener('click', () => {
info = Array.from(document.querySelectorAll('.card')).map(el => ({
image: el.querySelector('img').src,
word: el.querySelector('.input').dataset.word,
guess: el.querySelector('.input').value,
content: el.querySelector('.input').value === el.querySelector('.input').dataset.word ?
'Correct' : 'Incorrect'
}));
bindWords();
});
<div id="mainColumns"></div>
<button id="check">Check Answers</button>

How can i add an "onclick function" inside a `literal template` which is inside a Class?

this if my first question here, so sorry for any mistake or if the question is too silly.
*I have a Class with a method that displays a country-card on screen. I need to add an onclick function to save the name of the country so I can access to it from another page. i don't know if there is a way to make it work.
Any ideas?
class UI {
constructor() {
this.cardsContainer = document.querySelector("#cards-container");
}
showCountries(data) {
data.forEach(country => {
let div = `
<div class="card">
// this is the onclick function i need to access
<a onclick="countrySelected(${this.country.borders})">
<div class="card-image">
<img src=${country.flag} alt="">
</div>
<div class="card-info">
<h2 class="card-name"> ${country.name}</h2>
<p><strong>Population:</strong> ${country.population}</p>
<p><strong>Region:</strong> ${country.region}</p>
<p><strong>Capital:</strong> ${country.bogota}</p>
</div>
</a>
</div>
`;
this.cardsContainer.innerHTML += div;
})
}
//method
countrySelected(data) {
sessionStorage.setItem('country', data);
}
}
I assume that the country.name is unique.
class UI {
constructor() {
this.cardsContainer = document.querySelector("#cards-container");
}
showCountries(data) {
data.forEach(country => {
let div = `
<div class="card">
// this is the onclick function i need to access
<a id=${country.name}>
<div class="card-image">
<img src=${country.flag} alt="">
</div>
<div class="card-info">
<h2 class="card-name"> ${country.name}</h2>
<p><strong>Population:</strong> ${country.population}</p>
<p><strong>Region:</strong> ${country.region}</p>
<p><strong>Capital:</strong> ${country.bogota}</p>
</div>
</a>
</div>
`;
this.cardsContainer.innerHTML += div;
document.querySelector(`a[id="${country.name}"]`)
.addEventListener('click', () => countrySelected(country.borders));
})
}
//method
countrySelected(data) {
sessionStorage.setItem('country', data);
}
}
Also, you can refer to this post: Setting HTML Button`onclick` in template literal

Categories