I am working on a website that should have image sliders with clickable buttons that flip to the next image.
I was able to make a single slider / page, but as I have no experience in coding yet, I ran into difficulties when I was trying make multiple sliders following each other directly. The buttons of a certain slider started to mix up, and target other sliders too, or only the first one, but not the way I wanted..
So I started copying and repeating the same lines of code and applying them to groups of images separately.
I also want some text to flip together with the images, so I grouped the text and images together with the buttons, and finally I ended up having a lot of repetition, and way too long codes. :-)
Right now it works, but I assume that there is a much easier, solution, that would make my code a lot shorter.
Can someone help me with:
Having one good java script, that doesn't mix up the targets, when having multiple sliders?
Having only one "buttons"/slider instead of copying them to all the "containergrid"s groups, but still flipping the text together with the image?
Thanks, and sorry for the long code. :)
<div class="content">
<!---THE FIRST SLIDER--->
<div class="slider_1">
<div class="slides_1">
<div class="containergrid">
<div class="description">
<p class="maindescription">Description</p>
<p class="year">2017</p>
</div>
<div class="imgbutton">
<img class="img_1_1">
<div class="button">
<button class="prev"
onclick="plusDivs1(-1)"></button>
<button class="next"
onclick="plusDivs1(1)"></button>
</div>
</div>
</div>
</div>
<div class="slides_1">
<div class="containergrid">
<div class="description">
<p class="maindescription">Description</p>
<p class="year">2017</p>
</div>
<div class="imgbutton">
<img class="img_1_2">
<div class="button">
<button class="prev"
onclick="plusDivs1(-1)"></button>
<button class="next"
onclick="plusDivs1(1)"></button>
</div>
</div>
</div>
</div>
</div>
<!---THE SECOND SLIDER--->
<div class="slider_2">
<div class="slides_2">
<div class="containergrid">
<div class="description">
<p class="maindescription">Description</p>
<p class="year">2017</p>
</div>
<div class="imgbutton">
<img class="img_2_1">
<div class="button">
<button class="prev"
onclick="plusDivs1(-1)"></button>
<button class="next"
onclick="plusDivs1(1)"></button>
</div>
</div>
</div>
</div>
<div class="slides_2">
<div class="containergrid">
<div class="description">
<p class="maindescription">Description</p>
<p class="year">2017</p>
</div>
<div class="imgbutton">
<img class="img_2_2">
<div class="button">
<button class="prev"
onclick="plusDivs1(-1)"></button>
<button class="next"
onclick="plusDivs1(1)"></button>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var slideIndex = 1;
showDivs1(slideIndex);
function plusDivs1(n) {
showDivs1(slideIndex += n);
}
function showDivs1(n) {
var i;
var x = document.getElementsByClassName("slides_1");
if (n > x.length) { slideIndex = 1 }
if (n < 1) { slideIndex = x.length }
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
x[slideIndex - 1].style.display = "flex";
}
</script>
<script>
var slideIndex = 1;
showDivs2(slideIndex);
function plusDivs2(n) {
showDivs2(slideIndex += n);
}
function showDivs2(n) {
var i;
var x = document.getElementsByClassName("slides_2");
if (n > x.length) { slideIndex = 1 }
if (n < 1) { slideIndex = x.length }
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
x[slideIndex - 1].style.display = "flex";
}
</script>
So you would just have to pass a reference to your slides into the showDivs function, so you can keep the clicks independent of one another. You'd still have to initialize each slider separately.
function plusDivs(slider, n) {
showDivs(slider, slideIndex += n);
}
function showDivs(slider, index) {
var i;
var x = document.getElementsByClassName(slider);
if (index > x.length) {
slideIndex = 1
}
if (index < 1) {
slideIndex = x.length
}
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
x[slideIndex - 1].style.display = "flex";
}
// Initialize the sliders
var slideIndex = 1;
showDivs('slides_1', slideIndex);
showDivs('slides_2', slideIndex);
In your HTML you just need to pass the reference to the plusDivs function:
onclick="plusDivs('slides_1', 1)"
Here is a fiddle showing a working example
Related
Building a site with a slideshow. Trying to get the previous and next buttons functioning with JS. I would also like to be able to click the circle icons and have it take me to the desired slide in which was clicked. Below I have provided my html and JS.
Here is my html
'''
<!--slideshow container-->
<div id="slideContainer">
<!--full-width images with number-->
<div class="mySlides">
<div class="slideNumber">1 / 3</div>
<img src="images/uber-scuba-gili-TucvB6VLPAU-unsplash.jpg">
</div>
<div class="mySlides">
<div class="slideNumber">2 / 3</div>
<img src="images/chrisS-seychelles.jpg">
</div><div class="mySlides">
<div class="slideNumber">3 / 3</div>
<img src="images/danielC-barca.jpg">
</div>
<!--next and previous button-->
<a class="previous" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
</div>
<br>
<!--circle indicators-->
<div style="text-align: center;">
<span class="dot" onclick="currentSlide(1)"></span>
<span class="dot" onclick="currentSlide(2)"></span>
<span class="dot" onclick="currentSlide(3)"></span>
</div>
'''
here is my not functioning JS (sorry brand new to JS)
'''
var slideIndex = 0;
showSlides();
function showSlides() {
var i;
var slides = document.getElementsByClassName("mySlides");
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
slideIndex++;
if (slideIndex > slides.length) {slideIndex = 1}
slides[slideIndex-1].style.display = "block";
setTimeout(showSlides, 10000); // Change image every 10 seconds
}
var i = 0,mySlides;
function mySlides(param)
{
if (param === 'next')
{
i++;
if(i === slides.length) {i = slides.length - 1}
}else{
i--;
if(i < 0) {i = 0}
}
document.getElementsByClassName("mySlides").src = slides[i];
}
'''
Trying to make a kind of auto rotating banner for content in a footer. The issue is that whilst they update the slide, the first two stop after changing once, and the third updates faster than it should be doing. Each of the parts have unique class names, and I can't seem to find the problem. I believe the issue is either in the HTML or the JS scripts, however this is really the first time ive used multiple scripts on one page. (This is for a project)
HTML
<footer>
<div class = "grid-container" id = "footer-grid">
<div class = "grid-100 mobile-grid-100 grid-parent" id = "slideshow">
<div class = "Slide1 grid-33 mobile-grid-33">
<h1>Slide 1</h1>
</div>
<div class = "Slide1 grid-33 mobile-grid-33">
<h1>Slide 2</h1>
</div>
<div class = "Slide1 grid-33 mobile-grid-33">
<h1>Slide 3</h1>
</div>
<div class = "Slide1 grid-33 mobile-grid-33">
<h1>Slide 4</h1>
</div>
<div class = "Slide1 grid-33 mobile-grid-33">
<h1>Slide 5</h1>
</div>
<div class = "Slide grid-33 mobile-grid-33">
<h1>Slide 1</h1>
</div>
<div class = "Slide grid-33 mobile-grid-33">
<h1>Slide 2</h1>
</div>
<div class = "Slide grid-33 mobile-grid-33">
<h1>Slide 3</h1>
</div>
<div class = "Slide grid-33 mobile-grid-33">
<h1>Slide 4</h1>
</div>
<div class = "Slide grid-33 mobile-grid-33">
<h1>Slide 5</h1>
</div>
<div class = "mySlides3 grid-33 mobile-grid-33">
<h1>Slide 1</h1>
</div>
<div class = "mySlides3 grid-33 mobile-grid-33">
<h1>Slide 2</h1>
</div>
<div class = "mySlides3 grid-33 mobile-grid-33">
<h1>Slide 3</h1>
</div>
<div class = "mySlides3 grid-33 mobile-grid-33">
<h1>Slide 4</h1>
</div>
<div class = "mySlides3 grid-33 mobile-grid-33">
<h1>Slide 5</h1>
</div>
</div>
<div class = "clear"></div>
<div class = "clear"></div>
<div class = "grid-100" id = "footer-info">
<p>some stuff might go here</p>
</div>
</div>
</footer>
<!-- SCRIPTS -->
<script>
var slideIndex = 0;
carousel();
function carousel() {
var i;
var x = document.getElementsByClassName("Slide1");
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
slideIndex++;
if (slideIndex > x.length) {slideIndex = 1}
x[slideIndex-1].style.display = "block";
setTimeout(carousel, 1000); // Change image every 2 seconds
}
</script>
<script>
var slideIndex = 0;
carousel();
function carousel() {
var i;
var x = document.getElementsByClassName("Slide");
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
slideIndex++;
if (slideIndex > x.length) {slideIndex = 1}
x[slideIndex-1].style.display = "block";
setTimeout(carousel, 1000); // Change image every 2 seconds
}
</script>
<script>
var slideIndex = 0;
carousel();
function carousel() {
var i;
var x = document.getElementsByClassName("mySlides3");
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
slideIndex++;
if (slideIndex > x.length) {slideIndex = 1}
x[slideIndex-1].style.display = "block";
setTimeout(carousel, 1000); // Change image every 2 seconds
}
</script>
CSS
Slide1, .Slide, .mySlides3 {
display: none;
border: 1px solid black;
text-align: center;
padding-top:10px;
margin-bottom:10px;
}
Any help is appreciated, this is the only real issue i've had using javascript at this point. I can't seem to find why this is occurring, I have tried changing class names to be more distinct.
You can consolidate your javascript right now and make this much easier on yourself. You should only need 1 carousel function for all of your calls. The only things that changes between each carousel function call is the class name. So add that as a parameter for your carousel function.
<!-- SCRIPTS -->
<script>
var slideIndex = 0;
carousel("Slide1");
carousel("Slide");
carousel("mySlides3");
function carousel(slideName) {
var i;
var x = document.getElementsByClassName(slideName);
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
slideIndex++;
if (slideIndex > x.length) {
slideIndex = 1
}
x[slideIndex - 1].style.display = "block";
setTimeout(function() { carousel(slideName) }, 1000); // Change image every 2 seconds
}
</script>
PS... You are missing a "." on Slide1 in your css as well.
When you create a new function in global scope you are basically doing the following:
window.carousel = function () { ... }
You have 3 scripts parts. When first is executed, it rotates the first element. But after that, it's overwritten by second script block. So your code is something like this currently:
window.carousel = function () { /* logic for elm 1 */ }
window.carousel()
window.carousel = function () { /* logic for elm 2 */ }
window.carousel()
window.carousel = function () { /* logic for elm 3 */ }
window.carousel()
In short, 3 script tags share one scope, hence your problem.
Solution might be creating a carousel function which will take id as an argument. And this is better coding practice anyways
I want to display image caption under each images in image slider.
But right now my problem is all the image captions are displaying for each image like this
View :
<div class="grid-11 left">
#if (Model.Photos.Count > 0)
{
<div style="padding:10px">
<div class="slide-content" style="max-width:800px">
#foreach (var photos in Model.Photos)
{
<div>
<img class="mySlides" src="#Url.Content(photos.photo_url)"/>
</div>
<span>#photos.photo_caption</span>
}
<div class="w3-center">
<div class="w3-section">
<button class="w3-button w3-light-grey" onclick="plusDivs(-1)">❮ </button>
<button class="w3-button w3-light-grey" onclick="plusDivs(1)"> ❯</button>
</div>
</div>
</div>
</div>
}
</div>
Script :
var slideIndex = 1;
showDivs(slideIndex);
function plusDivs(n) {
showDivs(slideIndex += n);
}
function currentDiv(n) {
showDivs(slideIndex = n);
}
function showDivs(n) {
var i;
var x = document.getElementsByClassName("mySlides");
if (n > x.length) {
slideIndex = 1
}
if (n < 1) {
slideIndex = x.length
}
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
x[slideIndex - 1].style.display = "block";
}
How do is display caption for each image by passing image_id?
The problem is you're targeting the image only for display block/none via class="mySlides". You need to wrap the image and caption in some sort of container and target that instead.
#foreach (var photos in Model.Photos)
{
<div class="mySlides">
<div>
<img src="#Url.Content(photos.photo_url)"/>
</div>
<span>#photos.photo_caption</span>
</div>
}
I have 3 sliders on my page I'm a building but i am just curious to know the best way to go about targeting only the active one so the javascript below would work for all of them. Everything seems to work fine if i disable the other 2 sliders. First time I have done something like this.
I'm guessing my javascript selectors may need to change some what to get it to work.
Appreciate any advice on the best way forward.
var sliderSlide = document.querySelectorAll('.slider__slide');
var nextSlide = document.querySelector('.slider__button--next');
var previousSlide = document.querySelector('.slider__button--previous');
var currentSlide = 0;
var currentSlideImg = 0;
//Reset slides
function resetSlides() {
for (var s = 0; s < sliderSlide.length; s++) {
sliderSlide[s].classList.remove('active');
}
for (var i = 0; i < sliderSlideImg.length; i++) {
sliderSlideImg[i].classList.remove('active');
}
}
//Start slides
function startSlide() {
resetSlides();
sliderSlide[0].classList.add('active');
sliderSlideImg[0].classList.add('active');
}
//Previous slide
function slidePrevious() {
resetSlides();
sliderSlide[currentSlide - 1].classList.add('active');
currentSlide--;
sliderSlideImg[currentSlideImg - 1].classList.add('active');
currentSlideImg--;
}
previousSlide.addEventListener('click', function() {
if (currentSlide === 0 && currentSlideImg === 0) {
currentSlide = sliderSlide.length;
currentSlideImg = sliderSlideImg.length;
}
slidePrevious();
});
//Next slide
function slideNext() {
resetSlides();
sliderSlide[currentSlide + 1].classList.add('active');
currentSlide++;
sliderSlideImg[currentSlideImg + 1].classList.add('active');
currentSlideImg++;
}
nextSlide.addEventListener('click', function() {
if (currentSlide === sliderSlide.length - 1 && currentSlideImg === sliderSlideImg.length - 1) {
currentSlide = -1;
currentSlideImg = -1;
}
slideNext();
});
<div class="slider slider--1 active">
<div class="slider__slide">
<p class="slider__text">some text</p>
</div>
<div class="slider__slide">
<p class="slider__text">some text</p>
</div>
<div class="slider__slide">
<p class="slider__text">some text</p>
</div>
<div class="slider__buttons">
<span class="slider__button--previous">Previous</span>
<span class="slider__button--next">Next</span>
</div>
</div>
<div class="slider slider--2">
<div class="slider__slide">
<p class="slider__text">some text</p>
</div>
<div class="slider__slide">
<p class="slider__text">some text</p>
</div>
<div class="slider__slide">
<p class="slider__text">some text</p>
</div>
<div class="slider__buttons">
<span class="slider__button--previous">Previous</span>
<span class="slider__button--next">Next</span>
</div>
</div>
<div class="slider slider--3">
<div class="slider__slide">
<p class="slider__text">some text</p>
</div>
<div class="slider__slide">
<p class="slider__text">some text</p>
</div>
<div class="slider__slide">
<p class="slider__text">some text</p>
</div>
<div class="slider__buttons">
<span class="slider__button--previous">Previous</span>
<span class="slider__button--next">Next</span>
</div>
</div>
You can create loop over .slider and then use querySelector on each item, that way you will have variables for each slider
Array.from(document.querySelectorAll('.slider')).forEach(function(slider) {
var sliderSlide = slider.querySelectorAll('.slider__slide');
var nextSlide = slider.querySelector('.slider__buttons--next');
var previousSlide = slider.querySelector('.slider__buttons--previous');
...
});
or if you prefer for loop:
var sliders = document.querySelectorAll('.slider');
for (var i = 0; i < sliders.length; ++i) {
var slider = sliders[i];
...
}
document.querySelector('.slider--3 .slider__slide')
but I would recommend to put id's on your sliders and then select
document.querySelector('#slider--3')
I have a page with several buttons, when each button is clicked a different modal pops up. Some of the modals are carousels, the code I have works but for only one of the carousels, when I have more than one I get extra empty slides on all the carousels. So I'm guessing my code is counting all the slides from all the carousels together. Im trying to have write something where it says if this modal is clicked then get the slides from the clicked modal only but Im struggling with that.
These are the bits of relevant code:
<script>
//Carousel
var slideIndex = 1;
showDivs(slideIndex);
function plusDivs(n) {
showDivs(slideIndex += n);
}
function currentDiv(n) {
showDivs(slideIndex = n);
}
function showDivs(n) {
var i;
var x = document.getElementsByClassName("mySlides");
var dots = document.getElementsByClassName("demo");
if (n > x.length) {slideIndex = 1}
if (n < 1) {slideIndex = x.length}
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
/*dots[i].className = dots[i].className.replace(" w3-white", "");*/
}
x[slideIndex-1].style.display = "block";
/*dots[slideIndex-1].className += " w3-white";*/
}
</script>
<script>
//Display corresponding modal of letter that is clicked
$(".button").on("click", function() {
var modal = $(this).data("modal");
$(modal).show();
document.body.classList.add("modal-open");
});
//Close modal when "x" is clicked or when area outside modal is clicked
$(".modal").on("click", function(e) {
var className = e.target.className;
if(className === "modal" || className === "close"){
$(this).closest(".modal").hide();
document.body.classList.remove("modal-open");
}
});
</script>
<button class="button" data-modal="#modalOne"><img id="myImg" src=""></button>
<button class="button" data-modal="#modalB"><img id="myImg" src=""></button>
<button class="button" data-modal="#modalC"><img id="myImg" src=""></button>
<!-- The Modal -->
<div id="modalA" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="close">×</span>
<div class= "mySlides">
<img class="gif" src="" width="100" height="100" >
<h4>Title</h4>
<p> content </p>
</div>
<div class="mySlides">
<h4 Title</h4>
<p> content </p>
</div>
<div class="w3-left w3-hover-text-khaki" onclick="plusDivs(-1)">❮</div>
<div class="w3-right w3-hover-text-khaki" onclick="plusDivs(1)">❯</div>
</div>
</div>
<!-- The Modal B -->
<div id="modalB" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="close">×</span>
<div class="mySlides">
<img class="gif" src="" width="100" height="100" >
<h4></h4>
<p></p>
</div>
</div>
</div>
<!-- The Modal C -->
<div id="modalC" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="close">×</span>
<div class="mySlides">
<img class="gif" src="" width="100" height="100" >
<h4></h4>
<p></p>
<div class="mySlides">
<h4></h4>
<p></p>
</div>
<div class="w3-left w3-hover-text-khaki" onclick="plusDivs(-1)">❮</div>
<div class="w3-right w3-hover-text-khaki" onclick="plusDivs(1)">❯</div>
</div>
</div>
When you do this line
var x = document.getElementsByClassName("mySlides");
You count all the elements with class name of "mySlides", which is ALL of the slides in the HTML document.
Add code in your button click routine to count the number of slides in the corresponding modal:
Add this at the top of the javascript:
var modal = "modalA";
showDivs(slideIndex, modal);
Change the button click to:
$(".button").on("click", function() {
modal = $(this).data("modal").text();
$("#" + modal).show();
document.body.classList.add("modal-open");
});
Modify your showDivs function to include the new variable:
function showDivs(n, modal) {
var i;
var x = document.getElementById(modal).getElementsByClassName("mySlides");
var dots = document.getElementsByClassName("demo");
if (n > x.length) {slideIndex = 1}
if (n < 1) {slideIndex = x.length}
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
/*dots[i].className = dots[i].className.replace(" w3-white", "");*/
}
x[slideIndex-1].style.display = "block";
/*dots[slideIndex-1].className += " w3-white";*/
}
Finally, change the data-modal attributes of your buttons to read:
<button class="button" data-modal="modalA">
<button class="button" data-modal="modalB">
<button class="button" data-modal="modalC">
You will also need to update the lines:
function plusDivs(n) {
showDivs(slideIndex += n, modal);
}
function currentDiv(n) {
showDivs(slideIndex = n, modal);
}