Carousel - linking to slide from another page - why JS not working? - javascript

I'm trying to following this but it's 6 years old. Have things change 'cause my js doesn't seem to get triggered when the URL contains #slide_ ?
Linking to a certain bootstrap carousel slide from another page
My code on page2:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
<!-- Core theme CSS (includes Bootstrap)-->
<link href="css/styles.css?v20221223=1" rel="stylesheet" />
</head>
<body>
<!-- Carousel Wrapper-->
<div id="myCarousel" class="carousel carousel-dark slide" data-bs-interval="false" data-ride="carousel" data-pause="hover">
<div class="carousel-inner">
<div class="carousel-item active">
<img src="https://www.w3schools.com/bootstrap/chicago.jpg" alt="..." class="d-block img-fluid">
</div>
<div class="carousel-item">
<img src="https://www.w3schools.com/bootstrap/la.jpg" alt="..." class="d-block img-fluid">
</div>
<div class="carousel-item">
<img src="https://www.w3schools.com/bootstrap/ny.jpg" alt="..." class="d-block img-fluid">
</div>
</div>
</div>
</div>
<!-- END Carousel Wrapper-->
<!-- Bootstrap core JS - versionas as of Dec 2022-->
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<!-- JS for loading a particular slide from another page -->
<script>
function qs(key) {
key = key.replace(/[*+?^$.\[\]{}()|\\\/]/g, "\\$&");
var match = location.search.match(new RegExp("[?&]" + key + "=([^&]+)(&|$)"));
var slide = match && decodeURIComponent(match[1].replace(/\+/g, " "));
if (Math.floor(slide) == slide && $.isNumeric(slide))
return parseInt(slide);
else
return 0;
}
//why this isn't working???
$('#myCarousel').carousel(qs('slide'));
</script>
</body>
</html>
And the link on page 1
slide 2
I'm stuck...

In your example you added your JS in page 2, but your link redirects the user to page 1. Make sure you get your URLs correct, so based on your example it should be slide 2 on page 1.
Furthermore, the function function qs(key) {..} extracts the hash on ? not on #.
Don't worry though, what you want is simple, so I wrote a quick example for you.
Explaining the snippet below
You can achieve your desired functionality without needing jQuery.
In my example I created a function called getSlideNumber(). This first checks if the location hash exists, then we get it's value and split it on the = to get to the slide number. After that, we convert value into an integer using parseInt(). If that fails, the parseInt() function returns NaN so we also make sure our slide number is in fact an integer before we return it using Number.isInteger(). This way we protect ourselves against any malicious hashes.
We then call that function to get our slide number and use Bootstrap's method getOrCreateInstance to get the carousal instance that's on our page and make it cycle to the slide number using to().
And that's all it is!
Usage
We can't extract a hash in a snippet, so I don't call the function getSlideNumber() in my example. Therefore, make sure you delete the line const slideNumber = 2 and remove the // in front of the line above it when you want to use this code for your own project. Like so:
const slideNumber = getSlideNumber();
const element = document.querySelector('#carouselExample')
const caroursal = bootstrap.Carousel.getOrCreateInstance(element).to(slideNumber);
Also, note that the first slide of a carousal has an index of 0, similar to an array.
Lastly, you can edit the carousal HTML as you please, I used the basic example from the documentation.
The snippet
window.onload = function(){
function getSlideNumber() {
if(location.hash && location.hash.length) {
const value = location.hash.substr(1).split('=')[1];
const int = parseInt(value);
if (Number.isInteger(int)) {
return int;
} else {
return 0;
}
}
return 0;
}
//const slideNumber = getSlideNumber();
const slideNumber = 2; // Uncomment the line above and remove this line, it's only for demonstration purposes.
const element = document.querySelector('#carouselExample')
const caroursal = bootstrap.Carousel.getOrCreateInstance(element).to(slideNumber);
};
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>
<div class="container">
<div id="carouselExample" class="carousel slide">
<div class="carousel-inner">
<div class="carousel-item active">
<img src="https://www.w3schools.com/bootstrap/chicago.jpg" class="d-block w-100" alt="...">
</div>
<div class="carousel-item">
<img src="https://www.w3schools.com/bootstrap/la.jpg" class="d-block w-100" alt="...">
</div>
<div class="carousel-item">
<img src="https://www.w3schools.com/bootstrap/ny.jpg" class="d-block w-100" alt="...">
</div>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#carouselExample" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#carouselExample" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
</div>
Solution with jQuery
But wait! What if you can't live without jQuery? Worry no more, use this instead:
$(document).ready(function() {
function getSlideNumber() {
if(location.hash && location.hash.length) {
const value = location.hash.substr(1).split('=')[1];
const int = parseInt(value);
if (Number.isInteger(int)) {
return int;
} else {
return 0;
}
}
return 0;
}
const slideNumber = getSlideNumber();
$("#carouselExample").carousel(slideNumber);
});
Multiple carousals on one page
Assuming all carousals should be set to slideNumber we can target all carousals on the page with the class .carousal and then loop through them, like so:
const slideNumber = getSlideNumber();
const carousels = document.querySelectorAll('.carousel');
carousels.forEach(carousel => {
bootstrap.Carousel.getOrCreateInstance(carousel).to(slideNumber);
});
This works fine, but all carousals will cycle to the same slideNumber. If say your hash contains multiple values like page2.html#slide=2&slide=3 and you want the second carousal to cycle to slide 3 you would have to make getSlideNumber() return an object with all the slide numbers, then get the id of carousal inside the forEach loop and apply the corresponding slide number you have in the previous mentioned object in the to() method on the carousal id. That would be just one possible way of doing it.
Hope that helps. Good luck!

Related

Bootstrap carousel with Javascript function to play and pause

I have a problem in carousel class in bootstrap. I have defined a button which is by default a pause button, then i use a javascript function on that button to control the carousel like when clicked, the icon should change to play and the carousel should stop the cycle, but .click(function) is not working when the button is clicked instead it is pausing the carousel when i position the mouse on the button.
please help me solve this problem.
$(document).ready(function(){
$("#mycarousel").carousel( { interval: 2000 } );
$("#carouselButton").click(function()
{
if ($("#carouselButton").children("span").hasClass('fa-pause'))
{
$("#mycarousel").carousel("pause");
$("#carouselButton").children("span").removeClass('fa-pause');
$("#carouselButton").children("span").addClass('fa-play');
}
else if ($("#carouselButton").children("span").hasClass('fa-play'))
{
$("#mycarousel").carousel("cycle");
$("#carouselButton").children("span").removeClass('fa-play');
$("#carouselButton").children("span").addClass('fa-pause');
}
});
});
Nice question. I couldn't get { pause:null } to work as you wanted either. But digging this more, I got a working solution...
the key is toggling data-interval attribute on the carousel div
but this doesn't get the loop started, to trigger the start... we either have to hover-on and hover-off manually... or automate it (which we did)
but since there is some lag for adding/removing this attribute by jQuery, we (hackish-ly) add a setTimeout to take care of this
Working snippet below:
$(document).ready(function() {
$('#playPause').click(function() {
if ($("#myCarousel").attr("data-interval")) {
$("#myCarousel").removeAttr("data-interval");
$(".carousel-item>.active").removeAttr("active");
setTimeout(function() {
$(".carousel-control-next").trigger('click');
$(".carousel-inner").trigger('mouseenter');
$("#myCarousel").trigger('mouseenter');
}, 500);
} else {
$("#myCarousel").attr("data-interval", "500");
setTimeout(function() {
$(".carousel-control-next").trigger('click');
$(".carousel-inner").trigger('mouseenter');
$("#myCarousel").trigger('mouseenter');
$("#myCarousel").trigger('mouseleave');
}, 1000);
}
});
// Enable Carousel Indicators
$(".item1").click(function() {
$("#myCarousel").carousel(0);
});
$(".item2").click(function() {
$("#myCarousel").carousel(1);
});
$(".item3").click(function() {
$("#myCarousel").carousel(2);
});
// Enable Carousel Controls
$(".carousel-control-prev").click(function() {
$("#myCarousel").carousel("prev");
});
$(".carousel-control-next").click(function() {
$("#myCarousel").carousel("next");
});
});
/* Make the image fully responsive */
.carousel-inner img {
width: 100%;
height: 100%;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
<div class="container mt-3">
<button type='button' id='playPause'>Play / Pause</button>
<!-- The carousel -->
<div id="myCarousel" class="carousel slide mt-4">
<!-- Indicators -->
<ul class="carousel-indicators">
<li class="item1 active"></li>
<li class="item2"></li>
<li class="item3"></li>
</ul>
<!-- The slideshow -->
<div class="carousel-inner">
<div class="carousel-item active">
<img src="https://www.w3schools.com/bootstrap4/la.jpg" alt="Los Angeles" width="1100" height="500">
</div>
<div class="carousel-item">
<img src="https://www.w3schools.com/bootstrap4/chicago.jpg" alt="Chicago" width="1100" height="500">
</div>
<div class="carousel-item">
<img src="https://www.w3schools.com/bootstrap4/ny.jpg" alt="New York" width="1100" height="500">
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#myCarousel">
<span class="carousel-control-prev-icon"></span>
</a>
<a class="carousel-control-next" href="#myCarousel">
<span class="carousel-control-next-icon"></span>
</a>
</div>
</div>
I believe you left uncommented div with the same id:
<div class="btn-group" id="carouselButton">
then your button with the same id just doesn't work:
<button class="btn btn-danger btn-sm" id="carouselButton">
I had the same problem. The code comes from Coursera, Front-End Web UI Frameworks and Tools: Bootstrap 4 Week 4, Exercise (Instructions): More Bootstrap and JQuery
Answer below works well and in JavaScript for a different taste
function buttonFlip() {
var parentButton = document.getElementById("carouselButton");
var childSpan = document.getElementById("carouselButton_span");
if (parentButton.contains(childSpan) && childSpan.classList.contains("fa-pause")) {
$("#mycarousel").carousel('pause');
childSpan.classList.remove("fa-pause");
childSpan.classList.add("fa-play");
}
else {
$("#mycarousel").carousel('cycle');
childSpan.classList.remove("fa-play");
childSpan.classList.add("fa-pause");
}
}
If this is the bootstrap course lesson 4, from coursera, I had the same issue.
Go to this part and change the ID in my case I put carousel-style as id. Then go to the stylesheet and change the #carouselButton to the id you named in the btn-group.
It should work after that.
P.S The teacher doesnt explain to you but also you need to change the play icon to "fas fa play" as a class
it should look like this.
div class="btn-group" id="carousel-style">
<button class="btn btn-light btn-sm" id="carouselButton">
<span class="fa fa-pause"></span>
</button>
</div>
The Javascript should look like this:
<script>
$(document).ready(function() {
$('#mycarousel').carousel({ interval: 2000 });
$("#carouselButton").click(function(){
if ($("#carouselButton").children("span").hasClass('fa fa-pause')) {
$("#mycarousel").carousel('pause');
$("#carouselButton").children("span").removeClass('fa fa-pause');
$("#carouselButton").children("span").addClass('fas fa-play');
}
else if ($("#carouselButton").children("span").hasClass('fas fa-play')){
$("#mycarousel").carousel('cycle');
$("#carouselButton").children("span").removeClass('fas fa-play');
$("#carouselButton").children("span").addClass('fa fa-pause');
}
});
}); </script>

Get elements that don't contain a figure using plain javascript

I am trying to get all parent items that don't contain a figure. Then I will loop through that and wrap the images inside it in a figure if that figure does not already exist. I have successfully looped through and wrapped each image in a figure however if the figure already exists I want to do skip it. I am hoping to use only javascript and not jquery. Thanks for any help
HTML
<div class="carousel-item active">
<figure class="figure-image">
<img src="https://via.placeholder.com/350x150" class="Image-1" alt="Second Slider Slide">
</figure>
</div>
<div class="carousel-item">
<img src="https://via.placeholder.com/350x150" class="Image-2" alt="Second Slider Slide">
</div>
JS
This JS loops through and wraps all images in a figure but if a figure already exists as per my example above if will add a figure and way resulting in one element having two figures. I think the solution will be to just grab the carosuelItems without .figure-images inside right form the start but I am unsure how to do this.
let carouselItem = [...document.querySelectorAll('.slider-image .carousel-item')]
for (let i = 0; i < carouselItem.length; i++) {
// Check to see if a figurea lready exists
// Create a figure for each class and add class to it.
let figure = document.createElement('figure')
figure.classList.add('figure-image')
// Get all images inside of the slider
let carouselImg = [...carouselItem[i].querySelectorAll('img')]
for (let img of carouselImg) {
// Insert the images into each figure
figure.insertAdjacentElement('afterbegin', img)
}
// Finally insert the figure with the image into each carousel slot
carouselItem[i].insertAdjacentElement('afterbegin', figure)
}
You can check if the element has a child element <figure> using something like this: carouselItem[i].querySelector("figure")
Here is a complete example:
let carouselItem = [...document.querySelectorAll('.carousel-item')]
for (let i = 0; i < carouselItem.length; i++) {
if(!carouselItem[i].querySelector("figure")){
// Check to see if a figurea lready exists
// Create a figure for each class and add class to it.
let figure = document.createElement('figure')
figure.classList.add('figure-image')
// Get all images inside of the slider
let carouselImg = [...carouselItem[i].querySelectorAll('img')]
for (let img of carouselImg) {
// Insert the images into each figure
figure.insertAdjacentElement('afterbegin', img)
}
// Finally insert the figure with the image into each carousel slot
carouselItem[i].insertAdjacentElement('afterbegin', figure)
}
}
<div class="carousel-item active">
<figure class="figure-image">
<img class="Image-1" src="https://via.placeholder.com/350x150" alt="Second Slider Slide">
</figure>
</div>
<div class="carousel-item">
<img class="Image-2" src="https://via.placeholder.com/350x150" alt="Second Slider Slide">
</div>
This is from MDN Web Docs:
"Since the document fragment is in memory and not part of the main DOM tree, appending children to it does not cause page reflow (computation of element's position and geometry). Historically, using document fragments could result in better performance."
In my code I'm using the createDocumentFragment() method.
let imgs = Array.from(document.querySelectorAll("img"));
for(let i = 0; i < imgs.length; i++){
let img = imgs[i]
let parentdiv = img.parentNode;
if(parentdiv.tagName.toLowerCase() == "figure"){
continue;
}else{
let fragment = document.createDocumentFragment();
let figureParent = document.createElement("figure");
figureParent.setAttribute("class","figure-image");
figureParent.appendChild(img)
fragment.appendChild(figureParent);
parentdiv.appendChild(fragment)
}
}
figure{border:1px solid}
<div class="carousel-item active">
<figure class="figure-image">
<img class="Image-1" src="https://rpc.virtualhighschool.com/v3_demo/department/demo/course/ver-a/style_template_30/parts-of-a-cell.jpg" alt="Second Slider Slide">
</figure>
</div>
<div class="carousel-item">
<img class="Image-2" src="https://rpc.virtualhighschool.com/v3_demo/department/demo/course/ver-a/style_template_30/parts-of-a-cell.jpg" alt="Second Slider Slide">
</div>

How can I write variables so I don't have to repeat myself?

I'm using an animated modal called animatedModal.js
In order to have a modal fire on click, I have to register a new ID and class every time I need a new Modal. I'm writing this as static HTML, CSS, and JavaScript.
I don't want to register 49 classes and IDs when I know there's a more DRY way of doing so. How can I write this code so it finds classes and IDs and passes them into a function?
<div class="item box student-life">
<a class="demo2" href="#animatedModal-2">
<img class="responsive-img" src="img/design-3-cards-buttons-icon-update-final-design-TILES3_07.jpg">
<div class="content-card">
<h3 class="title">This is an example of a long headline. They Happen sometimes but, I won't let them destroy my layout. Not this time.</h3>
<h5 class="title">Service Learning</h5>
<div class="icon"><img src="img/icons/student-life.png" class="responsive-img" alt=""/></div>
<button class="btn pull-right">Read More</button>
</div>
</a>
</div>
<!--DEMO02 Window-->
<div id="animatedModal-2">
<!--THIS IS IMPORTANT! to close the modal, the class name has to match the name given on the ID class="close-animatedModal" -->
<div class="close-animatedModal-2">CLOSE MODAL</div>
<div class="modal-content"> <img class="responsive-img" src="img/ART-01024.jpeg">
<h1>Content for this block</h1>
</div>
</div>
JavaScript:
$("#demo01").animatedModal({
animatedIn:'zoomIn',
animatedOut:'bounceOut',
color:'#39BEB9',
beforeOpen: function() {
var children = $(".thumb");
var index = 0;
function addClassNextChild() {
if (index == children.length) return;
children.eq(index++).show().velocity("transition.expandIn", { opacity:1, stagger: 250 });
window.setTimeout(addClassNextChild, 200);
}
addClassNextChild();
},
afterClose: function() {
$(".thumb").hide();
}
});

Auto click bullets on slider to make slider autoplay for all slides

I have a custom slider which can rotate each image when I click the bullets. I need to make it autoplay, so I want if the page is ready, it's trigger click on the 1st bullet, 2nd, 3rd, 4th, etc and back to 1st bullet again...
but it just works for 1st and 2nd slides only.
The bullets using attr data-container for each slide id:
<nav class="thumb-nav">
<a data-container="container-1" class="thumb-nav__item" href="#"><span>1</span></a>
<a data-container="container-2" class="thumb-nav__item" href="#"><span>2</span></a>
<a data-container="container-3" class="thumb-nav__item" href="#"><span>3</span></a>
<a data-container="container-4" class="thumb-nav__item" href="#"><span>4</span></a>
</nav>
and these are the slide contents:
<div id="container-1" class="container theme-1">
<header class="intro">
<img class="intro__image" src="http://tympanus.net/Tutorials/SlidingHeaderLayout/img/header01.jpg" alt="Lava"/>
<!-- /intro__content -->
</header><!-- /intro -->
</div><!-- /container -->
<div id="container-2" class="container theme-2">
<header class="intro">
<img class="intro__image" src="http://tympanus.net/Tutorials/SlidingHeaderLayout/img/header02.jpg" alt="Road"/>
<!-- /intro__content -->
</header><!-- /intro -->
</div>
<div id="container-3" class="container theme-3">
<header class="intro">
<img class="intro__image" src="http://tympanus.net/Tutorials/SlidingHeaderLayout/img/header03.jpg" alt="Lava"/>
</header>
</div>
<div id="container-4" class="container theme-4">
<header class="intro">
<img class="intro__image" src="http://tympanus.net/Tutorials/SlidingHeaderLayout/img/header02.jpg" alt="Lava"/>
</header>
</div>
and here's my FIDDLE
Any help is going to be appreciated.
The setInterval is not supposed to be inside the forEach loop.
var pageIndex = 0;
setInterval(function() {
pageIndex ++;
if(pageIndex >= pageTriggers.length) pageIndex = 0;
navigate( pageTriggers[pageIndex] );
}, 5000);
Refer jsFiddle
Hope this helps. Let me know if your question is not answered.
Edit:
if(pageIndex >= pageTriggers.length)
Note:
I am creating a new pageIndex here, you might consider using your already defined global variable current.
First: You need to move your setInterval block outside of your outside of pageTriggers.forEach block. As you have it, it is creating a timer for each of the slides but then the first one is overriding the others (which is why it's only bouncing between your first two slides).
Second: Outside of the forEach you can't pass this to your navigate function. So you're going to need some other way of figuring out which slide to go to. That new slide is represented below by newIndex.
Solution:
setInterval(function () {
var newIndex = current + 1 >= pageTriggers.length ? 0 : current + 1
navigate(pageTriggers[newIndex]);
}, 5000);
See the fiddle.
Nice job though, I like it.

Bootstrap3 carousel - picking random next slide

I'm kind of stumped. :) I'm new to Javascript, but have typically found lots of great help on the net when I Googled. The best help I could come up with this time was here, but the docs said it was better to post a new question than sidetrack the original post. So, here's my question: I'm using Bootstrap3's carousel I'm trying to pick a random starting image, and then continue with random images after that. I've figured out how to pick the first slide, but can't figure out how to pick the next slide. As it stands, it just continues to cycle through the show.
<div id="myCarousel" class="carousel slide" data-wrap="true" data-ride="carousel">
<!-- Slider Content (Wrapper for slides )-->
<div class="carousel-inner">
<div class="item">
<img src="images/slides/AAA.jpg" alt="AAA" />
</div>
<div class="item">
<img src="images/slides/BBB.jpg" alt="BBB" />
</div>
<div class="item">
<img src="images/slides/CCC.jpg" alt="CCC" />
</div>
<div class="item">
<img src="images/slides/DDD.jpg" alt="DDD" />
</div>
<div class="active item">
<img src="images/slides/EEE.jpg" alt="EEE" />
</div>
</div>
</div>
<script src="js/bootstrap.js"></script>
<script type='text/javascript'>
$(document).ready(function() {
/* Pick a random number and apply it to the first slide in the slideshow item */
$('.item').eq(Math.floor((Math.random() * $('.item').length))).addClass("active");
/* Pick random next slide */
$('#myCarousel').carousel(Math.floor((Math.random() * $('.item').length))));
});
</script>
Thanks. :)
jQuery
var currentSlide;
var rand;
$(document).ready(function() {
currentSlide = Math.floor((Math.random() * $('.item').length));
rand = currentSlide;
$('#myCarousel').carousel(currentSlide);
$('#myCarousel').fadeIn(1000);
setInterval(function(){
while(rand == currentSlide){
rand = Math.floor((Math.random() * $('.item').length));
}
currentSlide = rand;
$('#myCarousel').carousel(rand);
},3000);
});
CSS
#myCarousel {
display:none;
}
HTML
<div id="myCarousel" class="carousel slide" data-wrap="true">
....
Well here is an example of how I would do it... I also accounted for the possibility of it randomly changing to the same slide.
http://www.bootply.com/99052
You will notice however that depending on which slide is chosen the carousel will transition either left or right.. The bootstrap carousel was designed to display linear images. There may be a way to manipulate the order of the items using jQuery so that it always slides the same way. If you are looking for that it could be done but would take some work and would probably be best handled in another question.
Als you can remove the data-ride="carousel" from you html and that will make it so the carousel will initialize without cycling.

Categories