How can I improve this simple image gallery code? - javascript

I'm trying to make a basic image gallery with simple html, css and js
This is the code so far.
$('.navigation-1').click(function() {
$('.cat-1').css("opacity", "1");
$('.cat-2').css("opacity", "0");
$('.cat-3').css("opacity", "0");
$('.cat-4').css("opacity", "0");
});
$('.navigation-2').click(function() {
$('.cat-1').css("opacity", "0");
$('.cat-2').css("opacity", "1");
$('.cat-3').css("opacity", "0");
$('.cat-4').css("opacity", "0");
});
$('.navigation-3').click(function() {
$('.cat-3').css("opacity", "1");
$('.cat-1').css("opacity", "0");
$('.cat-2').css("opacity", "0");
$('.cat-4').css("opacity", "0");
});
$('.navigation-4').click(function() {
$('.cat-4').css("opacity", "1");
$('.cat-1').css("opacity", "0");
$('.cat-2').css("opacity", "0");
$('.cat-3').css("opacity", "0");
});
.navigation {
margin-bottom: 15px;
}
.cat {
opacity: 0;
position: absolute;
transition: opacity 0.5s ease-in-out;
}
/* Show a picture at load */
.cat-1 {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<div class="navigation">
<button class="nav navigation-1">Cat 1</button>
<button class="nav navigation-2">Cat 2</button>
<button class="nav navigation-3">Cat 3</button>
<button class="nav navigation-4">Cat 4</button>
</div>
<img class="cat cat-1" src="http://placekitten.com/300/200" alt="">
<img class="cat cat-2" src="http://placekitten.com/300/201" alt="">
<img class="cat cat-3" src="http://placekitten.com/301/200" alt="">
<img class="cat cat-4" src="http://placekitten.com/301/201" alt="">
How do I dynamically generate the buttons and hide the other images, when one image is shown.
I used opacity to show and hide images, but feel free to use whatever suits you best.
I'm sure the this keyword is useful here, but how?

How about the following... where I've added a "data-index" attribute to the "navigation" buttons.
The on button click you hide all "cat" items, and then show the required one by targeting it using the "data-index" attribute.
$('.nav').click(function() {
$('.cat').css("opacity", "0");
var id = $(this).data("index");
$('.cat-' + id).css("opacity", "1");
});
.navigation {
margin-bottom: 15px;
}
.cat {
opacity: 0;
position: absolute;
transition: opacity 0.5s ease-in-out;
}
/* Show a picture at load */
.cat-1 {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<div class="navigation">
<button class="nav" data-index="1">Cat 1</button>
<button class="nav" data-index="2">Cat 2</button>
<button class="nav" data-index="3">Cat 3</button>
<button class="nav" data-index="4">Cat 4</button>
</div>
<img class="cat cat-1" src="http://placekitten.com/300/200" alt="">
<img class="cat cat-2" src="http://placekitten.com/300/201" alt="">
<img class="cat cat-3" src="http://placekitten.com/301/200" alt="">
<img class="cat cat-4" src="http://placekitten.com/301/201" alt="">

// get all cats
const cats = document.querySelectorAll('.cat')
// gets nav container
const nav = document.querySelector('.navigation')
// for each cat
for (let i = 0; i < cats.length; i++) {
// select current cat
const chosenCat = cats[i];
// create button for it
const button = document.createElement("button");
// add some text to button
button.innerHTML = `Cat ${i + 1}`;
// create onclick function that hides all cats and reveals current
button.onclick = () => {
// use Array.prototype.slice.call because you cant iterate the NodeList
Array.prototype.slice.call(cats).forEach(cat => cat.style.opacity = 0);
chosenCat.style.opacity = 1;
};
// add button to nav container
nav.appendChild(button);
}
// reveal initial cat
cats[0].style.opacity = 1;
.cat {
opacity: 0;
position: absolute;
transition: opacity 0.5s ease-in-out;
top: 0;
}
.navigation {
margin-top: 200px;
}
<img class="cat cat-1" src="http://placekitten.com/300/200" alt="">
<img class="cat cat-2" src="http://placekitten.com/300/201" alt="">
<img class="cat cat-3" src="http://placekitten.com/301/200" alt="">
<img class="cat cat-4" src="http://placekitten.com/301/201" alt="">
<div class="navigation">
</div>

Related

JavaScript Parent Node contains not working failed to execute 'contains' on 'Node'

I try to change the icon image on click.
I add a class active to make the bottom div appear then i check if the parentNode.contains("active") i should have an image else i should have another image
but this method it doesn't work and i recive this message
Failed to execute 'contains' on 'Node': parameter 1 is not of type
'Node'.
How can i fix this problem?
let drops = document.querySelectorAll('.drop');
let imgs = document.querySelectorAll('.drop .inner-right img');
drops.forEach((drop) => {
drop.addEventListener("click", function (e) {
drop.parentNode.classList.toggle("active");
imgs.forEach((img) => {
img.src = `../images/new icons/${e.currentTarget.dataset.img}`;
if(drop.parentNode.contains("active")){
}else{
img.src = `../images/${e.currentTarget.dataset.old}`;
}
});
});
});
.box.active .bottom {
opacity: 1;
visibility: visible;
}
.box .bottom {
opacity:0;
visibility: hidden;
}
<div class="box desc">
<div class="top drop" data-img="wasf al khotwa-01.svg" data-old="description.png">
<div class="inner-right">
<img src="images/description.png" alt="desc">
<p>Title</p>
</div>
<i class="fas fa-angle-down"></i>
</div>
<div class="bottom">
<p>
Text
</p>
</div>
</div>
you perform contains method on a node and not on the classList of the element
If you want to check if node have a specific class you can use
drop.parentNode.classList.contains("active")
let drops = document.querySelectorAll('.drop');
let imgs = document.querySelectorAll('.drop .inner-right img');
drops.forEach((drop) => {
drop.addEventListener("click", function(e) {
drop.parentNode.classList.toggle("active");
imgs.forEach((img) => {
img.src = `../images/new icons/${e.currentTarget.dataset.img}`;
if (drop.parentNode.classList.contains("active")) {
console.log('win')
} else {
img.src = `../images/${e.currentTarget.dataset.old}`;
}
});
});
});
.box.active.bottom {
opacity: 1;
visibility: visible;
}
.box.bottom {
opacity: 0;
visibility: hidden;
}
<div class="box desc">
<div class="top drop" data-img="wasf al khotwa-01.svg" data-old="description.png">
<div class="inner-right">
<img src="images/description.png" alt="desc">
<p>Title</p>
</div>
<i class="fas fa-angle-down"></i>
</div>
<div class="bottom">
<p>
Text
</p>
</div>
</div>

How can I add css class to the to the nested element using DOM?

I have four child divs inside the container div, every child div has a button, image, and text inside. Images have to be blurry and text has to be hidden by default.
And when the user clicks the button, the button should be hidden, image and text should become clear and visible.
I'm trying to add or remove CSS classes from elements using for loop, but that just doesn't work at all...
let btns = document.querySelectorAll(".btn");
let images = document.querySelectorAll(".img");
let imgTexts = document.querySelectorAll(".img-text");
images.forEach((el) => el.classList.add("blur"));
imgTexts.forEach((el) => el.classList.add("hidden"));
for (let i = 0; i < btns; i++) {
btns[i].addEventListener("click", function () {
btns[i].classList.add("hidden");
});
}
.blur {
filter: blur(8px);
-webkit-filter: blur(8px);
}
.hidden {
display: none;
}
<div class="container">
<div class="card">
<button class="btn">Open the Gift</button>
<img
src=""
alt="#" class="img">
<p class="img-text">CONGRATULATIONS🎉</p>
</div>
<div class="card">
<button class="btn">Open the Gift</button>
<img
src=""
alt="#" class="img">
<p class="img-text">CONGRATULATIONS🎉</p>
</div>
<div class="card">
<button class="btn">Open the Gift</button>
<img
src=""
alt="#" class="img">
<p class="img-text">CONGRATULATIONS🎉</p>
</div>
<div class="card">
<button class="btn">Open the Gift</button>
<img
src=""
alt="#" class="img">
<p class="img-text">CONGRATULATIONS🎉</p>
</div>
</div>
for (let i = 0; i < btns; i++) {
btns[i].addEventListener("click", function () {
btns[i].classList.add("hidden");
});
}
Here, in the conditions of the for loop, write "i < btns.length".
There is not a boundation that you can create only one class. You can create multiple classes and just on and add and remove the class according to your need.
example code
HTML
<img class = "image imageHidden" src = alt = >
<button class = "button buttonHidden">Click me</button>
now I created two classes at the same time I can use them to my need in javascript
CSS
.image {
visiblity: visible}
.imageHidden {
visibility: hidden}
.button {
visibility: visible}
.buttonHidden {
visibility: hidden}
now I used them in CSS that I can use in javascript
document.querySelector(".button").addEventListener("click",function () {
document.querySelector("img").classList.add("image");
document.querySelector("button").classList.add("buttonHidden");});
this code will hide the button and show the image you can use this method according to your need.

Why does my slider go blank after reaching the end?

I'm having a two issues/problems with the following slide.
It is a "double slider", so, two simultaneous slider in body section.
First is that when i reach the last image (9-nth, cos that much both sliders contain), the second slider continues to work properly (sliding images infinitely) but the first one just get blank.
Or if i click on previous button on begining then second doesn't work and images disapear, while the first one work nicely. Can't figure it out why. I've tried changing the "id" in the HTML and styling it but nothing change.
Second is, that i finally need to make it more dynamic, so, to avoid hardcoding images in the HTML and to putt them in JS and somehow append them in the DOM, but don't know what exactlly to do; creating an array, or using the "createElement"?
And which logic could be usable to actually include them in the DOM and have the following slider(s), considering the provided code?
Since it's my just second slider which i'm making, i found it pretty much hard, so any help/hint/advice is welcomed.
P.S Must be in jQuery and plugins excluded, so please don't provide any plugins links.
Thank you in advance.
var slides = $('.slide');
slides.first().before(slides.last());
$('button').on('click', function() {
// Selecting the slides
slides = $('.slide');
// Selecting button
var button = $(this);
// Register active slide
var activeSlide = $('.active');
// Next function
if (button.attr('id') == 'next') {
slides.last().after(slides.first());
activeSlide.removeClass('active').next('.slide').addClass('active');
}
// Previous function
if (button.attr('id') == 'previous') {
slides.first().before(slides.last());
activeSlide.removeClass('active').prev('.slide').addClass('active');
}
});
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.slider {
position: relative;
width: 100%;
height: 300px;
overflow: hidden;
}
.slide {
width: 100%;
height: 300px;
position: absolute;
transition: 0.6s ease;
transform: translate(-100%, 0);
}
.slide img {
width: 100%;
height: 300px;
}
.slide.active {
transform: translate(0, 0);
}
.slide.active~.slide {
transform: translate(100%, 0);
}
body {
text-align: center;
}
button {
margin-top: 20px;
border: none;
border-radius: 0;
background: aqua;
color: #333;
padding: 10px;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="slider">
<div class="slide active">
<img src="Assets/slider-image-1.jpg" alt="">
</div>
<div class="slide">
<img src="Assets/slider-image-2.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-3.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-4.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-5.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-6.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-7.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-8.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-9.jpg">
</div>
</div>
<div class="slider">
<div class="slide active">
<img src="Assets/slider-image-1.jpg" alt="">
</div>
<div class="slide">
<img src="Assets/slider-image-2.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-3.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-4.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-5.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-6.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-7.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-8.jpg">
</div>
<div class="slide">
<img src="Assets/slider-image-9.jpg">
</div>
</div>
<button id="previous"><img src="Assets/arrow-blue-left.png" alt=""></button>
<button id="next"><img src="Assets/arrow-blue-right.png" alt=""></button>
Your code doesn't work properly because the slides = $('.slide') variable contains all slides from both sliders. You have to manipulate the slides in the to sliders independently. The second failure is that in your example the first slide is the initial active slide. Only slides in range second -> penultimate are allowed. Working example here
function handleSlide(slider, direction) {
var slides = $(slider).find('.slide');
if(slides.length < 1) return;
// Register active slide
var activeSlide = $(slider).find('.active');
// Next function
if (direction == 'next') {
slides.last().after(slides.first());
activeSlide.removeClass('active').next('.slide').addClass('active');
}
// Previous function
if (direction == 'previous') {
slides.first().before(slides.last());
activeSlide.removeClass('active').prev('.slide').addClass('active');
}
}
$('button').on('click', function() {
var button = $(this);
handleSlide($("#slider1"), $(button).attr('id'));
handleSlide($("#slider2"), $(button).attr('id'));
});
Loading images dinamically: You can do that by defining an array which contains the images and you can append the images into the slider using the jQuery 'append' method. Working example on jsFiddle.
function fillSliders(slider, images) {
$(slider).empty();
for(var i = 0; i < images.length; i++) {
if(typeof images[i] == "string" && images[i] !== "") {
var active = (i == 1) ? " active" : "";
$(slider).append('<div class="slide'+active+'"><img src="'+images[i]+'"
alt="image-'+i+'" /></div>');
}
}
}
var images = ["image1.jpg", "image2.jpg","image3.jpg","image4.jpg"];
fillSliders($("#slider"), images);

Creating a Slide Show with Javascript and HTML

I am very new to web development and am trying to create a slide show using JavaScript and HTML. The problem I keep running into is that when I FIRST load my page all the slide show text overlaps after that the slideshow runs as expected.
var current = 0;
var slides = document.getElementsByClassName("slide");
setInterval(function() {
for (var i = 0; i < slides.length; i++) {
slides[i].style.opacity = 0;
}
slides[current].style.opacity = 1;
current = (current != slides.length - 1) ? current + 1 : 0;
}, 2500);
.logo{
width:100px;
margin-left: 850px;
margin-top: -90px;
vertical-align:top;
}
.show {
position: absolute;width:500px; height:200px; left:50%; top:50%; margin-top: -140px;margin-left: -250px;
transition: opacity .5s ease-in;
}
.descrip {
text-align: center;
display: block;
position: absolute;width:500px; left:50%; top:50%; margin-top: 100px;margin-left: -250px;
transition: opacity .5s ease-in;
}
h1{
text-align: center;
margin-top: 130px;
}
<!DOCTYPE html>
<html>
<head>
<title>Tourism Slide Show</title>
<link href = "travelPics.css" rel = "stylesheet" type = "text/css">
<script type="text/javascript" src ="travelSlideShow.js"></script>
</head>
<body >
<h1>Uncle Phil's Tourism</h1>
<img src ='images/logo.jpg' class = "logo" alt = "logo">
<div class = "slide" >
<img src="images/athens.jpg" alt="Athens" class="show" >
<h2 class = "descrip">
Acropolis of Athens in Athens Greece <br>
The ruins of a 5th-century B.C temple.
</h2>
</div>
<div class = "slide">
<img src="images/burjkhalifa.jpg" alt="Burj Khalifa" class="show">
<h2 class = "descrip">The tallest structure in the world, standing at 829.8 m<br>Located in Dubai, United Arab Emirates</h2>
</div>
<div class = "slide">
<img src="images/cappadocia.jpg" alt="Cappadocia" class="show">
<h2 class = "descrip">
Located in central Turkey, is known for the Bronze Age homes carved into valley walls
</h2>
</div>
<div class = "slide">
<img src ="images/florence.jpg" alt ="Florence" class="show">
<h2 class = "descrip">
The Cathedral of Santa Maria del Fiore and Piazza Duomo <br>
Contains art and architecture by the greatest artists of the Italian Renaissance -- Ghiberti, Brunelleschi, Donatello, Giotto, and Michelangelo.
</h2>
</div>
<div class = "slide">
<img src = "images/lighthouse.jpg" alt ="Lighthouse" class="show">
<h2 class = "descrip"> Light house </h2>
</div>
<div class = "slide">
<img src = "images/louvre.jpg" alt = "Louvre" class="show">
<h2 class = "descrip"> Louvre</h2>
</div>
<div class = "slide">
<img src = "images/victoriafalls.jpg" alt = "Victoria Falls" class="show">
<h2 class = "descrip">Victoria falls </h2>
</div>
<div class = "slide">
<img src = "images/warmuseum.jpg" alt = "Canadian War Museum" class="show">
<h2 class = "descrip"> War Museum</h2>
</div>
</body>
</html>
Transform the first js part into the following:
//And manually call update once or at initial loading
//E.g. in jquery: $(document).on("load", update);
update();
setInterval(update, 2500);
function update()
{
for (var i = 0; i < slides.length; i++) {
slides[i].style.opacity = 0;
}
slides[current].style.opacity = 1;
current = (current != slides.length - 1) ? current + 1 : 0;
}
The reason for this is that setInterval will call the function after 2,5 seconds for the very first time. So you should manually call it initially.

Adding navigation buttons below my slider

I created a fade slider with images, text and links. I'd like to add some navigation bullets below it to control the images.
like this :
http://www.parallaxslider.com/preview_images/skins/bullets_skin.jpg
Here is the slider code:
html
<div class="slides">
<div class="slidiv">
<a href="..." ><img src="..." >
<span> text1 </span></a>
</div>
<div class="slidiv">
<a href="..." ><img src="..." >
<span> text2 </span></a>
</div>
<div class="slidiv">
<a href="..." ><img src="..." >
<span> text3 </span></a>
</div>
<div class="slidiv">
<a href="..." ><img src="...">
<span> text4 </span></a>
</div>
</div>
CSS
.slides {
overflow:hidden;
top:0;
position:relative;
width:100%;
height:206px;
z-index:920;
border-bottom:white 6px solid;
}
.slides img {
position:absolute;
left:0;
top:0;
}
.slides span {
position: absolute;
right: 100px;
top: 160px;
color:white !important;
font-size:20px;
}
Javascript
<script type="text/javascript">
$(function() {
$('.slides .slidiv:gt(0)').hide();
setInterval(function () {
$('.slides').children().eq(0).fadeOut(2000)
.next('.slidiv')
.fadeIn(2000)
.end()
.appendTo('.slides');
}, 6000); // 6 seconds
});
</script>
You have to define a unique id for each slide, then build html for circles (make sure you have a way of referencing which circle matches up to which slide). Then you capture the on click event, clear the interval, cycle forward until the slide in the "current" position matches the circle, then create the interval again. And of course every time it cycles forward you need to set a visual cue for the circle associated with the active slide.
(Demo)
HTML
<div class="slider">
<div class="slides">
<div class="slidiv" id="1">
<a href="...">
<img src="http://placehold.it/350x150/3296fa/ffffff">
<span>text1</span>
</a>
</div>
<div class="slidiv" id="2">
<a href="...">
<img src="http://placehold.it/350x150/fa9632/ffffff">
<span>text2</span>
</a>
</div>
<div class="slidiv" id="3">
<a href="...">
<img src="http://placehold.it/350x150/ff3399/ffffff">
<span>text3</span>
</a>
</div>
<div class="slidiv" id="4">
<a href="...">
<img src="http://placehold.it/350x150/33ff99/ffffff">
<span>text4</span>
</a>
</div>
</div>
<div class="circles">
</div>
</div>
CSS
.circles, .circle {
display: inline-block;
}
.circles {
position: relative;
left: 50%;
transform: translateX(-50%);
}
.circle {
padding: 5px;
border-radius: 100%;
border: 1px solid #444;
}
.active {
background: rgb(50, 150, 250);
}
JAVASCRIPT
$(function () {
$('.slides .slidiv:gt(0)').hide();
$.fn.setActive = function () {
if ($(this).hasClass("slider")) {
$(".active", $(this)).removeClass("active");
$("#circle-" + $(".slidiv:first-child", $(this),$(this)).attr("id"),$(this)).addClass("active");
return this;
}
return false;
}
$.fn.cycleFwd = function(rateStart,rateEnd) {
if ($(this).hasClass("slider")) {
$('.slides', $(this)).children()
.eq(0)
.fadeOut(rateStart)
.next('.slidiv')
.fadeIn(rateEnd)
.end()
.appendTo($('.slides', $(this)));
$(this).setActive($('.slidiv:first-child',$(this)).attr("id"));
return this;
}
return false;
}
$.fn.cycleFwdTo = function (id,rate) {
if($(this).hasClass("slider")) {
var current = $(".slidiv:first-child", $(this));
if(current.attr("id") === id) return true;
var count = id;
if(current.attr("id") > id) {
count = Number(current.nextAll().length) + Number(id) + 1;
}
if(count - current.attr("id") === 1) {
$(this).cycleFwd(rate,2000);
} else {
$(this).cycleFwd(rate,0);
$(this).cycleFwdTo(id,0);
}
return this;
}
return false;
}
$(".circle").on("click", function () {
clearInterval(window.interval);
var newFirst = $(this).attr("data-moveto");
$(this).parent().parent().cycleFwdTo(newFirst,2000);
var self = this;
window.interval = setInterval(function () {
$(self).parent().parent().cycleFwd(2000,2000);
}, 6000); // 6 seconds
});
$('.slider').each(function(){
var self = this;
window.interval = setInterval(function () {
$(self).cycleFwd(2000,2000);
}, 6000); // 6 seconds
});
});
EDIT:
This answer is not very good because it does not very well explain how it works, but this falls into "I could write a novel" explaining all of the different methods of doing what the OP has asked and how each method works. If someone else wanted to come along and offer better explanations of how this code works, I would approve.

Categories

Resources