I am learning JS with a little website project and stumbled upon the following problem:
I have an image gallery with a couple of pictures
I can always see 5 pics at a time
one is big in the middle, left and right a second row and 2 more in the background
I already have two buttons to rotate through the gallery. now I want to make it possible to be able to rotate the gallery by clicking the pics on the left or right side of the middle picture.
The HTML gallery
<div class="gallery-container">
<img class="gallery-item gallery-item-1" src="pictures/pic1.jpg" data-index="1">
<img class="gallery-item gallery-item-2 prev-pic" src="pictures/pic2.jpg" data-index="2">
<img class="gallery-item gallery-item-3" src="pictures/pic3.jpg" data-index="3">
<img class="gallery-item gallery-item-4 next-pic" src="pictures/pic4.jpg" data-index="4">
<img class="gallery-item gallery-item-5" src="pictures/pic5.jpg" data-index="5">
</div>
my Javascript
const galleryContainer = document.querySelector('.gallery-container');
let galleryItems = document.querySelectorAll('.gallery-item');
let galleryArray = Array.prototype.slice.call(galleryItems);
let prevPic = document.querySelector('.gallery-item.gallery-item-2.prev-pic');
let listenerPrev = prevPic.addEventListener('click', function(prevEvent) {
galleryArray.unshift(galleryArray.pop());
updateGallery();
});
let nextPic = document.querySelector('.gallery-item.gallery-item-4.next-pic');
let listnerNext = nextPic.addEventListener('click', function(nextEvent) {
galleryArray.push(galleryArray.shift());
updateGallery();
});
// Update css classes for gallery
function updateGallery() {
galleryArray.forEach(el => {
el.classList.remove('gallery-item-1');
el.classList.remove('gallery-item-2');
el.classList.remove('gallery-item-3');
el.classList.remove('gallery-item-4');
el.classList.remove('gallery-item-5');
el.classList.remove('prev-pic');
el.classList.remove('next-pic');
});
galleryArray.slice(0, 5).forEach((el, i) => {
el.classList.add(`gallery-item-${i+1}`);
});
document.querySelector('.gallery-item.gallery-item-2').classList.add('prev-pic');
document.querySelector('.gallery-item.gallery-item-4').classList.add('next-pic');
prevPic = document.querySelector('.gallery-item.gallery-item-2.prev-pic');
nextPic = document.querySelector('.gallery-item.gallery-item-4.next-pic');
}
My plan is to click the 'prevPic' and rotate the gallery. The first time clicking it works fine: the gallery rotates and the classes are updated. But when I click the new 'prevPic' it does nothing. What i noticed in my browser is that the 'event'-tag thats added in the html in the devoloper console doesnt move.
I hope someone understands my attempt to explain the matter and can help me out.
Thanks in advance
I would completely rethink my approach and do something like this, where I don't even store any of the elements as references; when a click happens I just look at what was clicked and react based on that. Would something like this work for your case?
document.querySelector(".gallery-container").addEventListener("click", (e) => {
if (e.target.classList.contains("prev")) {
if (e.target.previousElementSibling) {
e.target.previousElementSibling.classList.toggle("prev");
e.target.classList.toggle("prev");
e.target.nextElementSibling.nextElementSibling.classList.toggle("next");
e.target.nextElementSibling.classList.toggle("next");
} else {
alert("Cannot go more previous than this, friendo")
}
}
if (e.target.classList.contains("next")) {
if (e.target.nextElementSibling) {
e.target.nextElementSibling.classList.toggle("next");
e.target.classList.toggle("next");
e.target.previousElementSibling.classList.toggle("prev");
e.target.previousElementSibling.previousElementSibling.classList.toggle("prev");
} else {
alert("Cannot go more next than this, friendo")
}
}
});
.prev {border: 2px solid red;}
.next {border: 2px solid blue;}
<div class="gallery-container">
<img class="gallery-item" src="http://placekitten.com/50/50">
<img class="gallery-item prev" src="http://placekitten.com/49/49">
<img class="gallery-item" src="http://placekitten.com/48/48">
<img class="gallery-item next" src="http://placekitten.com/47/48">
<img class="gallery-item" src="http://placekitten.com/46/46">
</div>
Thank you for your answer. I tried it out, but in the end found a slightly different way, that works better for me (but your approch gave me the idea):
I kept my function updateGallery() where I move the class name around my pics after the gallery got shifted
function updateGallery() {
galleryArray.forEach(el => {
el.classList.remove('gallery-item-1');
el.classList.remove('gallery-item-2');
el.classList.remove('gallery-item-3');
el.classList.remove('gallery-item-4');
el.classList.remove('gallery-item-5');
el.classList.remove('next');
el.classList.remove('prev');
});
galleryArray.slice(0, 5).forEach((el, i) => {
el.classList.add(`gallery-item-${i+1}`);
});
galleryArray[1].classList.add('prev');
galleryArray[3].classList.add('next');
}
But access it this time but looping through the gallery:
for (var i=0; i<galleryArray.length; i++) {
galleryArray[i].addEventListener ('click', function(e) {
if (this.classList.contains('prev')) {
galleryArray.unshift(galleryArray.pop());
updateGallery();
} else if (this.classList.contains('next')) {
galleryArray.push(galleryArray.shift());
updateGallery();
}
})
}
Related
I'm starting out at coding and I'm stuck in a code that I'm working on.
First I pass the mouse inside my DIV container called "Article" and everything inside change its opacity. I want just the image that is inside's opacity changed, so everywhere inside the DIV the opacity of the image should be 1. Once the mouse is out the opacity of the image should become 0.75. I tried multiple codes but the opacity changed for every element inside the DIV. Hope you could help me.
I tried to change document . getElementsByTagName ('article') [i] by document.getElementsByTagName('img')[i] but it just changed the image opacity when mouse is over the image.
I tried document.getElementsByTagName('article')[i].getElementsByTagName('img')[i] same as before.
I tried to change this.style by img.style nothing happened...
for (var i = 0; i<document.querySelectorAll('article').length;i++)
document.getElementsByTagName('article')[i].onmouseover=function(){
this.style.opacity = 1;
}
for (var i = 0; i<document.querySelectorAll('article').length;i++)
document.getElementsByTagName('article')[i].onmouseleave=function(){
this.style.opacity = 0.75;
}
Hope that when I pass over an article the image opacity changes.
Thanks, you all an have a great year!
Try using querySelectorAll('article img') instead of getElementsByTagName. This will only affect img inside article.
Thanks Guys in fact at the end I change to css and it works perfectly sorry for being such a noobie and say that this doesn't work. I named my Article (DIV) "Dad" and my image "child".
OMG it was to simple and I complicate my life by a lot.
This is my final code:
.Dad:hover .Child {
opacity: 1;
}
I'm not sure what are you asking for, but check this:
HTML
<div class="container">
<h3>this is container</h3>
<img src="https://picsum.photos/200/300/?123" alt="">
<img src="https://picsum.photos/200/300/?14" alt="">
<img src="https://picsum.photos/200/300/?15" alt="">
</div>
CSS
.container{
background: #d87300;
}
.half-transparent{
opacity: 0.5;
}
JS
const images = [...document.querySelectorAll('.container img')]
const container = document.querySelector('.container')
container.addEventListener('mouseenter', ()=>{
images.forEach(element => {
element.classList.add('half-transparent')
})
})
container.addEventListener('mouseleave', ()=>{
images.forEach(element => {
element.classList.remove('half-transparent')
})
})
I am creating a simple Memory card game. I have the structure and card designs set up with CSS, now I just need to enable the actual playing of the game.
I need to have only two clicks allowed at a time. If the two cards match, the cards are removed. If the two cards don't match, they are "flipped" back over.
...I am only including the first row of the game, even though it is a 4x4 setup.
HTML
<div class="cardHolder">
<div id="card1" class="card" onClick="revealBlueCard()"></div>
<div id="card2" class="card" onClick="revealGreenCard()"></div>
<div id="card3" class="card" onClick="revealGreenCard()"></div>
<div id="card4" class="card" onClick="revealBlueCard()"></div>
</div>
JAVASCRIPT
// blue cards
var card1Ref = document.getElementById("card1");
var card4Ref = document.getElementById("card4");
card1Ref.addEventListener("click", revealBlueCard);
card4Ref.addEventListener("click", revealBlueCard);
function revealBlueCard(event){
event.target.style.backgroundColor = "#2155a8";
event.target.innerHTML = "<p>8</p>";
}
// green cards
var card2Ref = document.getElementById("card2");
var card3Ref = document.getElementById("card3");
card2Ref.addEventListener("click", revealGreenCard);
card3Ref.addEventListener("click", revealGreenCard);
function revealGreenCard(event){
event.target.style.backgroundColor = "#3cb260";
event.target.innerHTML = "<p>3</p>";
}
I am still very new to Javascript. I am assuming I am using a click event for "card" and applying if statements. I am also wondering if I need to apply data attributes to each card.
Why don't you add classes to the cards like blue class and green class.
CSS:
.blue{
background: #2155a8;
}
.green{
background: #3cb260
}
and also use event delegation (try to avoid adding event listeners to each card)
document.querySelector('#cardHolder').addEventListener('click', function(evt){
var clickedCard = evt.target;
if(clickedCard.classList.contains('blue'){
//do whatever for blue card
} else if(clickedCard.classList.contains('green')){
//do whatever for green card
}
});
there's a better way:
Use
onclick="cardClicked(this)"
for all your cards.
then in js
function cardClicked(elCard) {
if (elCard.classList.contains('flipped')) {
return;
}
// Flip it
elCard.classList.add('flipped');
I'm trying to make Previous and Next buttons cycle through src's and onclick's with already-visible images and of course, change others.
I'm doing this in JavaScript/HTML/CSS only, I don't know JQuery..
HTML fields:
<img id="prev" onclick="prev1()" src="Template.gif" width="64" height="64">
<img id="center" onclick="center1()" src="middlePictureOne.gif" width="128" height="128">
<img id="next" onclick="next1()" src="next.gif" width="64" height="64">
Previous Button script:
function prev1() {
document.getElementById("center").src="middlePictureOne.gif";
document.getElementById("center").onclick="center1()";
document.getElementById("next").onclick="next1()";
document.getElementById("prev").src="Template.gif";
}
Next Button:
function next1() {
if (condition == "true") {
document.getElementById("center").src="middlePictureTwo.gif";
document.getElementById("center").onclick="center2()";
document.getElementById("next").onclick="next2()";
document.getElementById("prev").onclick="prev1()";
document.getElementById("prev").src="previous.gif";
}else{
alert("Nope.");
}}
Condition: works, Next: works, Previous: having all the problems.
I've tried everything I know how to do to fix it.. just hoping the answer isn't so obvious..
Condition and how it's come to be:
var condition = new Boolean(0);
function center1() {
if (m1hp>0) {
m1hp -= (heroDamage - m1def);
} else {
onFinish();
}
document.getElementById("hpc").innerHTML=m1hp;
}
function onFinish() {
m1hp = 50;
condition = "true";
}
Lots of irrelevant info there, but I didn't want to leave anything out in case it matters..
http://jsfiddle.net/SusuReedJango/P7KNh/
THere's the fiddle completely unedited of everything I have written.. I'm stumped and cutting out the unused parts, it wouldn't work. Probably need to replace the images if you're that motivated to solve my problem.
I create simple grid application using basic grid example in visual studio and this tutorial. I expected this animation will work on all item's, but it seems that it works only on first one. My question is, how can I animate this on all item's? And if it is possible to animate randomly(not all at once! Example: windows 8 start menu).
Item template:
<div class="itemtemplate" data-win-control="WinJS.Binding.Template">
<div class="item">
<img class="item-image" src="#" data-win-bind="src: backgroundImage; alt: title" />
<img class="item-image-new" src="#" data-win-bind="src: backgroundImage; alt: title" />
<div class="item-overlay">
<h4 class="item-title" data-win-bind="textContent: title"></h4>
<h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: subtitle"></h6>
</div>
</div>
</div>
Js animation:
var darkGray = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY3B0cPoPAANMAcOba1BlAAAAAElFTkSuQmCC";
var lightGray = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY7h4+cp/AAhpA3h+ANDKAAAAAElFTkSuQmCC";
var mediumGray = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY5g8dcZ/AAY/AsAlWFQ+AAAAAElFTkSuQmCC";
// Play the Peek animation
function peekTile(tile1, tile2) {
// Create peek animation
var peekAnimation = WinJS.UI.Animation.createPeekAnimation([tile1, tile2]);
// Reposition tiles to their desired post-animation position
tile1.style.top = "-250px";
tile2.style.top = "0px";
// Execute animation
peekAnimation.execute();
}
function changeImage() {
// Get the two image elements
var images = document.querySelector(".item-image");
var imagesNew = document.querySelector(".item-image-new");
// Swap out the old image source and choose the new image source
images.src = imagesNew.src;
if (images.src == lightGray)
imagesNew.src = mediumGray;
else if (images.src == mediumGray)
imagesNew.src = darkGray;
else
imagesNew.src = lightGray;
// Reset the elements for the pre-animation position and trigger the animation
images.style.top = "0px";
imagesNew.style.top = "250px";
peekTile(images, imagesNew);
};
And interval, that changes images(it is written inside ready function):
setInterval(function () { changeImage() }, 4000);
When you call document.querySelector it will only return the first matching element, which in your case will be the first list item. If you want to animate any random item, just call document.querySelectorAll(".item"), pick a random item from the result list and then call querySelector('.item-image') on it, proceeding as you currently do.
I have some images and some span text on my page. Each image has his text and those elements are added dynamicaly with javascript.
Now, I would like to show the right message when mouseover on an image is detected.
It is not easy to explain, so here is the example:
var len = article_affiliations.length;
for (var affiliation_id = 0; affiliation_id < len; affiliation_id++)
{
$('#country_warning' + affiliation_id).mouseover(function () {
document.getElementById('country_warning_message' + affiliation_id)
.style.visibility = 'visible';
}).mouseout(function () {
document.getElementById('country_warning_message' + affiliation_id)
.style.visibility = 'hidden';
});
}
The problem is that when the onmouseover function will be called, the affiliation_id will have the maximum value and the message will be shown near the last image, and not near the clicked one.
Thank you very much for your help.
Closure should do the trick:
for(var affiliation_id=0; affiliation_id<article_affiliations.length; affiliation_id++) {
(function(i){
$('#country_warning'+i).mouseover(function() {
$('#country_warning_message'+i).css('visibility','visible');
}).mouseout(function(){
$('#country_warning_message'+i).css('visibility','hidden');
});
})(affiliation_id);
}
You'll need to bind your for loop in a closure for this to work. This way, all indices of #country_warning_i will be affected.
$(function () {
$.each(article_affiliations, function (i, v) {
$('#country_warning' + i).mouseover(function (affiliation_id, affiliation_iddddd) {
$('country_warning_message' + i).style.visibility = 'visible';
}).mouseout(function (i, affiliation_iddddd) {
$('country_warning_message' + i).style.visibility = 'hidden';
});
});
});
Enjoy and good luck!
You shouldn't do it with a loop that will just go through everyone of your elements. The best way of doing something like this is using the 'event.target'(built in jQuery) and 'this' objects.
Instead attach a mouseover event handler to the parent of your . The best is if your markup looks something like this:
<div class="item">
<img src="someimage.jpg" />
<span>some text</span>
</div>
<div class="item">
<img src="someimage.jpg" />
<span>some text</span>
</div>
<div class="item">
<img src="someimage.jpg" />
<span>some text</span>
</div>
That way you can use a script similar to this one:
$('.item').on('mouseover', function() {
$(this).find('span').show();
});
This will search for a span (every span) inside the element you attached the mouseover event to (for this ex the ).
Another way is to use simple css like this:
span {
visibility: hidden;
}
item:hover span {
visibility: visible;
}
This is an extremely simple solution and works beautifully, but unfortunately IE6 doesn't support hover on elements different from .