JavaScript not triggering events when dynamically loaded - javascript

I'm using the Swiper.js library and I have an issue getting the 'slideChange' event to trigger when dynamically loading elements through JavaScript.
Here is where my swipers both horizontal and vertical are initialised:
var swiper = {
initialize : function() {
swiperH = new Swiper('.swiper-container-h', {
slidesPerView: 1,
preloadImages: false,
updateOnImagesReady: true,
lazy: true,
})
.on('slideChange', function () {
console.log('Swiped Horizonally');
});
swiperV = new Swiper('.swiper-container-v', {
direction: 'vertical',
slidesPerView: 1,
preloadImages: false,
updateOnImagesReady: true,
lazy: true,
effect: 'fade',
loop: true,
fadeEffect: {
crossFade: true
},
pagination: {
el: '.swiper-pagination-v',
clickable: true,
},
})
.on('slideChange', function () {
console.log('Swiped Vertically');
});
}
};
The reason why the horizontal's 'slideChange' triggers is because its already in the html file:
<!-- Swiper -->
<div class="dash-container">
<div class="swiper-container swiper-container-h">
<div class="swiper-wrapper" id="swipeData">
</div>
</div>
</div>
Now, the vertical slides are loading through JavaScript and that's where the vertical's 'slideChange' doesn't trigger.
function loadDresses(selectedDresses) {
return new Promise((resolve, reject) => {
$('#swipeData').html('');
for (var i = 0; i < selectedDresses.length; i++) {
var vScroll = '<div class="swiper-slide"><div class="swiper-container swiper-container-v"><div class="swiper-wrapper" style="height: 100%;">';
for (var j = 0; j < selectedDresses[i].images.length; j++) {
vScroll += '<div class="swiper-slide"><img src="' + selectedDresses[i].images[j] + '"/></div>';
}
vScroll += '<div class="swiper-slide" style="display:table;height:100%;width:100%;">';
vScroll += '</div></div></div><div class="swiper-pagination swiper-pagination-v">';
$('#swipeData').append(vScroll).trigger('create');
}
resolve(true);
});
}
The error occurs at this snippet:
.on('slideChange', function () {
console.log('Swiped Vertically');
});
Any ideas? Thanks!
Edit:
I have tried the following to stop it from initialising too early, but still no luck:
loadDresses(dresses).then(function(result) {
var t = setInterval(() => {
swiper.initialize();
clearInterval(t);
}, 5000);
});

And doesn't that help?
var swiper = {
initialize : function() {
swiperH = new Swiper('.swiper-container-h', {
slidesPerView: 1,
preloadImages: false,
updateOnImagesReady: true,
lazy: true,
})
.on('slideChange', function () {
console.log('Swiped Horizonally');
});
swiperV = new Swiper('.swiper-container-v', {
direction: 'vertical',
slidesPerView: 1,
preloadImages: false,
updateOnImagesReady: true,
lazy: true,
effect: 'fade',
loop: true,
fadeEffect: {
crossFade: true
},
pagination: {
el: '.swiper-pagination-v',
clickable: true,
},
on: {
slideChange: function() {
console.log('Swiped Vertically');
}
}
});
}
};

You have some options here:
To keep the flow of your application, you can destroy the slider and reinitialize it.
swiperH.destroy()
then
loadDresses();
swiper.initialize();
OR
you can just mySwiper.update() every time you change your slide manually

The problem is that an element with class swiper-pagination-v is not found during initialization.
You can make condition for class swiper-pagination-v exists.
var swiper = {
initialize : function() {
swiperH = new Swiper('.swiper-container-h', {
slidesPerView: 1,
preloadImages: false,
updateOnImagesReady: true,
lazy: true,
})
.on('slideChange', function () {
console.log('Swiped Horizonally');
});
if ($('.swiper-container-v').length > 0) {
swiperV = new Swiper('.swiper-container-v', {
direction: 'vertical',
slidesPerView: 1,
preloadImages: false,
updateOnImagesReady: true,
lazy: true,
effect: 'fade',
loop: true,
fadeEffect: {
crossFade: true
},
pagination: {
el: '.swiper-pagination-v',
clickable: true,
},
})
.on('slideChange', function () {
console.log('Swiped Vertically');
});
}
}
};

Related

Delay initial running/starting of Swiper.js autoplay

I have a Swiper.js carousel that autoplays. I also fade in my page using DOMContentLoaded. This means that the first slide has changed or is in the middle of changing when the page comes into view. So it's in view a much shorter amount of time compared to the others.
Is it possible to delay the initial running of the autoplay carousel? I know you can add a delay to individual slides - but if I do that to counter it, it means 2nd time around the first slide lags/is in view longer than the rest.
JavaScript code:
window.addEventListener('DOMContentLoaded', function() {
document.body.className = 'visible';
});
var caption = document.querySelector('.swiper-caption span');
new Swiper('.swiper', {
// Disable preloading of all images
preloadImages: true,
// Enable lazy loading
lazy: false,
effect: 'fade',
fadeEffect: {
crossFade: true
},
loop: true,
autoplay: {
delay: 1200,
disableOnInteraction: false,
pauseOnMouseEnter: true
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev'
},
pagination: {
el: '.swiper-pagination',
type: 'fraction'
},
on: {
init: function() {
updateCaptionText(this);
},
activeIndexChange: function() {
updateCaptionText(this);
}
}
});
function updateCaptionText(slider) {
caption.textContent = slider.slides[slider.activeIndex].dataset.caption;
}
CSS code:
body.hidden {
opacity: 0;
}
body.visible {
opacity: 1;
transition: opacity .48s .24s ease-out;
}
Call swiper.autoplay.stop() just after setting it up, and call swiper.autoplay.start() inside DOMContentLoaded event handler. Like so:
const swiper = new Swiper(".swiper", {
// Disable preloading of all images
preloadImages: true,
// Enable lazy loading
lazy: false,
effect: "fade",
fadeEffect: {
crossFade: true,
},
loop: true,
autoplay: {
delay: 1200,
disableOnInteraction: false,
pauseOnMouseEnter: true,
},
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
},
pagination: {
el: ".swiper-pagination",
type: "fraction",
},
on: {
init: function () {
updateCaptionText(this);
},
activeIndexChange: function () {
updateCaptionText(this);
},
},
});
swiper.autoplay.stop();
window.addEventListener("DOMContentLoaded", () => {
document.body.className = "visible";
swiper.autoplay.start();
});
If you wanna delay the inital start even further, to match it with your CSS animation duration, you can use a setTimout, like this:
window.addEventListener("DOMContentLoaded", () => {
document.body.className = "visible";
setTimeout(() => swiper.autoplay.start(), 1000); // 1000 means 1s, it's in ms here.
});
Live example here at this CodePen I forked. References of used methods are here on Swiper.js's official doc.

Swiper 5.4.5 thumbs gallery multiple instances not working in same page

Swiper 5.4.5 thumbs gallery multiple instances not working in the same page swiper version 5.4.5
var galleryThumbs = new Swiper('.gallery-thumbs', {
spaceBetween: 10,
slidesPerView: 4,
loop: true,
freeMode: true,
loopedSlides: 5, //looped slides should be the same
watchSlidesVisibility: true,
watchSlidesProgress: true,
});
var galleryTop = new Swiper('.gallery-top', {
spaceBetween: 10,
loop: true,
loopedSlides: 5, //looped slides should be the same
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
thumbs: {
swiper: galleryThumbs,
},
});
/**
* Multiple Swiper Slides
* #require Swiper v4.X
* #author palash chandra
* #author website palashchandra.xyz
*/
const multipleSwiperSlides = function() {
let sliderMain = document.querySelectorAll('.swiper-container.js-slider--main')
let sliderNav = document.querySelectorAll('.swiper-container.js-slider--nav')
let mainArray = [];
let navArray = [];
// Slider Main
sliderMain.forEach(function(element, i) {
// Push swiper instance to array
mainArray.push(
new Swiper(element, {
loop: true,
loopedSlides: 3,
})
);
});
// Slider Nav
sliderNav.forEach(function(element, i) {
var self = sliderNav;
// Push swiper instance to array
navArray.push(
new Swiper(element, {
slidesPerView: 3,
loop: true,
loopedSlides: 3,
slideToClickedSlide: true,
spaceBetween: 5,
navigation: {
nextEl: self[i].querySelector('.swiper-button-next'),
prevEl: self[i].querySelector('.swiper-button-prev')
}
})
);
});
const checkOnPage = function() {
if (sliderMain.length > 0 && sliderNav.length > 0) {
let numberOfSlides = mainArray.length || navArray.length || 0;
if (mainArray.length !== navArray.length) {
console.warn('multipleSwiperSlides: Number of main slides and nav slides is different. Expect incorrect behaviour.');
}
for (let i = 0; i < numberOfSlides; i++) {
mainArray[i].controller.control = navArray[i];
navArray[i].controller.control = mainArray[i];
}
console.log('multipleSwiperSlides: Things should be working fine. B)');
}
}
checkOnPage();
}
multipleSwiperSlides();

swiper.js | Stop swiper slide autoplay on mouse enter and start autoplay on mouse leave

How to stop swiper slide autoplay on mouse enter and start autoplay on mouse leave? I have tried .stopAutoplay() and .startAutoplay() function but not worked for me.
This is my output : click here
And here is the js code :
<script>
var slider = new Swiper ('#slider', {
slidesPerView: 1,
autoplay: 1000,
spaceBetween: 0,
loop: true,
loopedSlides: 6,
centeredSlides : true,
 disableOnInteraction: true,
autoplayDisableOnInteraction: false,
nextButton: '.swiper-button-next',
prevButton: '.swiper-button-prev',
slidesPerView: '1.3',
breakpoints: {
600: {
slidesPerView: 1
}
}
});
var thumbs = new Swiper('#thumbs', {
centeredSlides: true,
spaceBetween: 10,
loopedSlides: 6,
loop: true,
slidesPerView: "auto",
touchRatio: 0.2,
slideToClickedSlide: true,
breakpoints: {
600: {
slidesPerView: 3
}
}
});
slider.params.control = thumbs;
thumbs.params.control = slider;
$("#slider").mouseenter(function() {
slider.autoplay.stop();
});
$("#slider").mouseleave(function() {
slider.autoplay.start();
});
$("#thumbs").mouseenter(function() {
thumbs.autoplay.stop();
});
$("#thumbs").mouseleave(function() {
thumbs.autoplay.start();
});
</script>
Try to use $el element returned from instance. It works fine.
slider.$el.on('mouseover', () => {
slider.autoplay.stop();
});
slider.$el.on('mouseleave', () => {
slider.autoplay.start();
});
Check this example:
https://codepen.io/keitoliveira/pen/XWKdXMr

Swiper wrapper didn't update when I update swiper instance (Swiper JS)

I have four buttons to show/hide slide card based on user selection. I show all products by default in total 10 cards. When changed to other options (the slide that only have four cards), there is a white space left. I tried to update with $productSlider.update() but it didn't work.
Demo Code (codesandbox)
Swiper Init
let $productSlider = new Swiper('.plan-slider-container', {
init: false,
observer: true,
observeParents: true,
observeSlideChildren: true,
spaceBetween: 0,
mousewheel: {
releaseOnEdges: true,
forceToAxis: true
},
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
keyboard: true,
scrollbar: {
el: '.swiper-scrollbar',
draggable: true,
hide: false,
},
breakpoints: {
320: {
slidesPerView: 1,
},
768: {
freeMode: true,
slidesPerView: 'auto'
}
}
});
User Selection Button
$('.choice-plan-btn-wrapper.desktop').on('click', e => {
let target = e.target;
let id = target.getAttribute('id');
let $parent = $(target).parent();
let lastActiveSiblingId = $(target).siblings('.active').attr('id');
if (target.tagName.toLowerCase() != 'button' || target.classList.contains('active')) return;
// button
$(target).addClass('active')
.siblings('.active').removeClass('active');
/* The Problem */
$parent.siblings('.plans-swiper-wrapper')
.children(`.${id}`).fadeIn('slow')
.siblings().not(`.${id}`).fadeOut('slow');
$productSlider.update();
/* The Problem */
$parent.siblings('.swiper-scrollbar')
.removeClass(`${lastActiveSiblingId}`)
.addClass(`${id}`)
$productSlider.slideTo(0, 500);
});

How can I minimize the code lines using (for each)

swiper one
var swiperCurrent;
var swiper = new Swiper('.swiper-container-1', {
init: false,
pagination: '.swiper-pagination-1',
nextButton: '.swiper-button-next-1',
prevButton: '.swiper-button-prev-1',
slidesPerView: 3,
centeredSlides: true,
paginationClickable: true,
initialSlide: 2,
spaceBetween: 22,
breakpoints: {
992: {
slidesPerView: 1,
spaceBetween: 10
}
},
runCallbacksOnInit:true
});
function showSliderContent2(idx) {
$('._ooredoo_banner_content_1> div').hide(0);
$('._ooredoo_banner_content_1> div:eq('+ idx +')').fadeIn(200)
}
swiper.on('init', function (el) {
showSliderContent(el.activeIndex);
});
swiper.on('transitionEnd', function (el) {
if(swiperCurrent !== el.activeIndex){
showSliderContent(el.activeIndex);
swiperCurrent = el.activeIndex;
}
});
swiper.init();
swiper two
var swiperCurrent2;
var swiper = new Swiper('.swiper-container-2, {
init: false,
pagination: '.swiper-pagination-2',
nextButton: '.swiper-button-next-2',
prevButton: '.swiper-button-prev-2',
slidesPerView: 3,
centeredSlides: true,
paginationClickable: true,
initialSlide: 2,
spaceBetween: 22,
breakpoints: {
992: {
slidesPerView: 1,
spaceBetween: 10
}
},
runCallbacksOnInit:true
});
function showSliderContent2(idx) {
$('._ooredoo_banner_content_2> div').hide(0);
$('._ooredoo_banner_content_2> div:eq('+ idx +')').fadeIn(200)
}
swiper.on('init', function (el) {
showSliderContent2(el.activeIndex);
});
swiper.on('transitionEnd', function (el) {
if(swiperCurrent2 !== el.activeIndex){
showSliderContent2(el.activeIndex);
swiperCurrent2 = el.activeIndex;
}
});
swiper.init();
swiper three
var swiperCurrent3;
var swiper = new Swiper('.swiper-container-3’, {
init: false,
pagination: '.swiper-pagination-3',
nextButton: '.swiper-button-next-3',
prevButton: '.swiper-button-prev-3',
slidesPerView: 3,
centeredSlides: true,
paginationClickable: true,
initialSlide: 2,
spaceBetween: 22,
breakpoints: {
992: {
slidesPerView: 1,
spaceBetween: 10
}
},
runCallbacksOnInit:true
});
function showSliderContent3(idx) {
$('._ooredoo_banner_content_3> div').hide(0);
$('._ooredoo_banner_content_3> div:eq('+ idx +')').fadeIn(200)
}
swiper.on('init', function (el) {
showSliderContent3(el.activeIndex);
});
swiper.on('transitionEnd', function (el) {
if(swiperCurrent3 !== el.activeIndex){
showSliderContent3(el.activeIndex);
swiperCurrent3 = el.activeIndex;
}
});
swiper.init();
Something like the following (untested) code might help: All I did was to factor out the common code into a reusable function and use template strings to fill in the missing parts, then map that function over the 1, 2, and 3 partial ids. This means we no longer need the 2 and 3 suffixes on some of the variables; they are only available inside the closures generated by the callback to map.
There are likely bugs in this, either reusing something I shouldn't or the reverse: making something dynamic that doesn't have to be. In the first case, if you can continue to use the id to distinguish it, great. If not, you might need one ore more additional variables, and the map statement will have to get a little more complex.
const makeSwiper = (id) => {
var swiperCurrent;
var swiper = new Swiper('.swiper-container-2', {
init: false,
pagination: `.swiper-pagination-${id}`,
nextButton: `.swiper-button-next-${id}`,
prevButton: `.swiper-button-prev-${id}`,
slidesPerView: 3,
centeredSlides: true,
paginationClickable: true,
initialSlide: 2,
spaceBetween: 22,
breakpoints: {
992: {
slidesPerView: 1,
spaceBetween: 10
}
},
runCallbacksOnInit:true
});
function showSliderContent(idx) {
$(`._ooredoo_banner_content_${id}> div`).hide(0);
$(`._ooredoo_banner_content_${id}> div:eq(${idx})`).fadeIn(200)
}
swiper.on('init', function (el) {
showSliderContent(el.activeIndex);
});
swiper.on('transitionEnd', function (el) {
if(swiperCurrent !== el.activeIndex){
showSliderContent(el.activeIndex);
swiperCurrent = el.activeIndex;
}
});
return swiper
}
const swipers = [1, 2, 3].map(makeSwiper)

Categories