nolimits4web / swiper

Most modern mobile touch slider with hardware accelerated transitions
https://swiperjs.com
MIT License
39.58k stars 9.75k forks source link

Swiping on a slide does not update the pagination active state on iOS Devices #2915

Closed vtatarinov closed 11 months ago

vtatarinov commented 5 years ago

This is a (multiple allowed):

What you did

We have a slider with the following basic settings: pagination: { el: '.swiper-pagination', },

Expected Behavior

When swiping on an iOS device, the pagination buttons should register an active class state change for the correct bullet.

Actual Behavior

Swiping on a slide does not update the pagination active state. Emulating touch on Chrome works but real devices or emulators for iOS show the bug.

nolimits4web commented 5 years ago

Can't see such issue, would be good to see live example or JSFiddle

techytuppers-zz commented 5 years ago

@nolimits4web - Hello! We have the same issue as reported here. Have upgraded to 4.5.0 locally and issue remains.

Example: https://www.rapha.cc/gb/en/collections/pro-team/category/pro-team (v 4.4.2) This is replicable in BrowserStack using real device

We do find it can be intermittent which adds complication!

techytuppers-zz commented 5 years ago

To add to the investigation here, it seems that on devices where this is an issue, the contents of the Swiper object is very different. Duplicate properties seem to exist?

functioning-correctly functioning-incorrectly

In order to get around the original pagination issue, I tried to force a pagination update carousel.on("slideChange", function() { carousel.pagination.update(); });

This appears to help initially, until the user scrolls, the carousel exits the viewport, and then the user scrolls back in, the pagination.update(); appears to no longer work. The slideChange runs, but the pagination.update() doesn't appear to have any effect.

AxelHo commented 5 years ago

Hi, Same Problem with simulateTouch on Desktop Browsers. Any news here?

VaninaDzhuteva commented 5 years ago

Hi, Same Problem with simulateTouch on Desktop Browsers. Any news here?

Hello, I have the same issue. Is there any progress on that topic? Thanks!

moi12fre commented 5 years ago

I got the same issue, please help.

Thanks.

pankrashov commented 4 years ago

I got the same issue, please help.

csmithcreative commented 4 years ago

I've got the same issue also. I tried the same fix as @techytuppers too, prior to finding this thread. Is this ever going to be fixed? Did anyone find a workaround? Pretty desperate here.

csmithcreative commented 4 years ago

I've finally found a fix for this after 2 days.

Just to clarify, this issue only occurs when using the bulleted pagination option. It does not happen when using the fraction or scrollbar options.

Device: iPhone 7 OS: iOS 13.3.1

Solution: Use the hashNavigation approach as detailed here - https://github.com/nolimits4web/Swiper/blob/master/demos/330-hash-navigation.html

Step 1 - Add the data-hash markup.

<div class="swiper-slide" data-hash="slide1">
    <!-- your content -->
</div>
<div class="swiper-slide" data-hash="slide2">
    <!-- your content -->
</div>
<div class="swiper-slide" data-hash="slide3">
    <!-- your content -->
</div>

Step 2 - Add the config to the script.


    var swiper = new Swiper('.swiper-container', {
        hashNavigation: {
            watchState: true,
        },
        pagination: {
            el: '.swiper-pagination',
            clickable: true,
        },
    });
MarkHTML commented 4 years ago

For me, where I had multiple sliders on a page it was becoming an issue, actually the last slider would control the first sliders dots. However specifying a unique ID instead of a class for the swiper pagination element did the trick. For me I dynamically create the pagination element with a unique ID for each instance before I create a new swiper js instance, then I pass that unique ID as the 'pagination el' in the option. var uniquie_id = 'pagination-'+Math.floor(Math.random() * 10000); var bullets_html = '<div class="swiper-pagination" id="'+uniquie_id+'"></div>'; swiperEl.innerHTML += bullets_html; var bullets_el = '#'+uniquie_id;

Then I specify that ID later:

pagination: { el: bullets_el, clickable: true },

yacovonthego commented 4 years ago

I've finally found a fix for this after 2 days.

Just to clarify, this issue only occurs when using the bulleted pagination option. It does not happen when using the fraction or scrollbar options.

Device: iPhone 7 OS: iOS 13.3.1

Solution: Use the hashNavigation approach as detailed here - https://github.com/nolimits4web/Swiper/blob/master/demos/330-hash-navigation.html

Step 1 - Add the data-hash markup.

<div class="swiper-slide" data-hash="slide1">
    <!-- your content -->
</div>
<div class="swiper-slide" data-hash="slide2">
    <!-- your content -->
</div>
<div class="swiper-slide" data-hash="slide3">
    <!-- your content -->
</div>

Step 2 - Add the config to the script.

    var swiper = new Swiper('.swiper-container', {
        hashNavigation: {
            watchState: true,
        },
        pagination: {
            el: '.swiper-pagination',
            clickable: true,
        },
    });

This solution for me forces vertical scroll, on blocks with hash attribute, is there any other workaround?

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

IamCrism commented 3 years ago

I've finally found a fix for this after 2 days.

Just to clarify, this issue only occurs when using the bulleted pagination option. It does not happen when using the fraction or scrollbar options.

Device: iPhone 7 OS: iOS 13.3.1

Solution: Use the hashNavigation approach as detailed here - https://github.com/nolimits4web/Swiper/blob/master/demos/330-hash-navigation.html

Step 1 - Add the data-hash markup.

<div class="swiper-slide" data-hash="slide1">
    <!-- your content -->
</div>
<div class="swiper-slide" data-hash="slide2">
    <!-- your content -->
</div>
<div class="swiper-slide" data-hash="slide3">
    <!-- your content -->
</div>

Step 2 - Add the config to the script.

    var swiper = new Swiper('.swiper-container', {
        hashNavigation: {
            watchState: true,
        },
        pagination: {
            el: '.swiper-pagination',
            clickable: true,
        },
    });

@csmithcreative To be clear, your solution does not work with the bulleted pagination. If i have to use the bulleted pagination (for example as preview-images) there is currently no solution right?

janwram commented 3 years ago

I had the same issue and used custom pagination as workaround:

CSS:

<style>
    .swiper-container-horizontal > .swiper-pagination-custom .swiper-pagination-bullet {
      margin: 0 4px;
    }
 </style>

JS:

var swiper = new Swiper('.swiper-container', {
      pagination: {
        el: '.swiper-pagination',
        clickable: true,
        type: 'custom',
        renderCustom: function (swiper, current, total) {
          var out = ''
          for (i = 1; i < total+1; i++) {
            if (i == current) {
              out = out + '<span class="swiper-pagination-bullet swiper-pagination-bullet-active" tabindex='+i+' role="button" aria-label="Go to slide '+i+1+'"></span>';
            }
            else {
              out = out + '<span class="swiper-pagination-bullet" tabindex='+i+' role="button" aria-label="Go to slide '+i+1+'"></span>';
            }
          };
          return out;
        },
      }
});,
bobmagicii commented 3 years ago

it is not just iOS, my work pc is a windows touch screen and it suffered in firefox as well. and only if i swiped with either finger or mouse. if i clicked the arrows, it did would work as expected.

using bullet pagination, no hash tracking, no tricks with calling .update() (trust me my dudes, i tried them all with you) i was able to fix this just by giving each container its own unique id so that new Swiper only ever touches ONE swiper at a time.

if i give each slider a unique id like so

<div id="swiper-container-wtf1" class="swiper-container">

and the only allow new Swiper to touch that one

new Swiper('#swiper-container-wtf1',{ ... })

everything works as expected, even where there are multiple on the page.

in reality our php template system generates a UUID and uses that to id and call the constructor that way i don't have to try.

<div id="swiper-container-<?php $Printer($UUID) ?>" class="swiper-container">
let UUID = <?php echo json_encode($UUID) ?>;
new Swiper(`#swiper-container-${UUID}`,{ ... });
pa22le commented 3 years ago

I had same issue.

Just in my case, calling twice over swiper function. Cause I am checking size of the slider with window.resize, that is calling Swiper few or several times on loaded. On the Desktop brawsers are OK, but on iPhone or iOS does not work well navigation and pagenation.

So I pull out swiper code from window resize function. Solved.

Yoroshiku.

TruongDuyIT commented 2 years ago

I got the same issue, please help.

gleenk commented 2 years ago

Still bugged also on desktop

andrecuellar commented 2 years ago

In my case I'm using multiple swiper containers inside a @foreach directive

On alpineJS (working on vanillaJS) my solution is add an ID for each swiper container

on my main container inside a foreach

@foreach($section->details()->get() as $index => $detail)
        <div class="swiper w-full h-72">
        <!-- More Code -->
@endforeach

I added an Id according to the $index

<div id="swiper-container-{{$index}}" class="swiper w-full h-72">

So, in the init swiper I replaced the class for the created ID

I replaced this swiper = new Swiper('.swiper',

for this

swiper = new Swiper('#swiper-container-{{$index}}',

the same for the wrapper content, I added data-hash and ID+1 according to the $index in nested foreach

@foreach($detail->getMedia('post-medias') as $index => $media)
            <div class="swiper-slide flex justify-center" data-hash="slide{{$index+1}}">
                    <img class="h-64"
                             src="{{$media->getUrl()}}">
            </div>
@endforeach

and it works correctly!

my AlpineJS entire code

@foreach($section->details()->get() as $index => $detail)
                    <div class="py-2"
                             x-data="{swiper: null, SwiperNavigation, SwiperPagination}"
                             x-init="swiper = new Swiper('#swiper-container-{{$index}}',
                        {
                            modules: [SwiperNavigation, SwiperPagination],
                            loop: true,
                            slidesPerView: 'auto',
                            centeredSlides: true,
                            spaceBetween: 30,
                            hashNavigation: {
                                watchState: true,
                            },

                            pagination: {
                            el: '.swiper-pagination',
                            clickable: true,
                            },

                            navigation: {
                            nextEl: '.swiper-button-next',
                            prevEl: '.swiper-button-prev',
                            },
                        })">
                            <div id="swiper-container-{{$index}}" class="swiper w-full h-72">
                                <div class="swiper-wrapper">
                                    @foreach($detail->getMedia('post-medias') as $index => $media)
                                        <div class="swiper-slide flex justify-center" data-hash="slide{{$index+1}}">
                                            <img class="h-64"
                                                 src="{{$media->getUrl()}}">
                                        </div>
                                    @endforeach
                                </div>
                                <div class="swiper-pagination"></div>
                                <div class="swiper-button-prev"></div>
                                <div class="swiper-button-next"></div>
                            </div>
                        </div>
@endforeach

my laravel-mix app.js resource file

import Swiper, { Navigation, Pagination } from 'swiper';
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';

window.Swiper = Swiper;
window.SwiperNavigation = Navigation;
window.SwiperPagination = Pagination;
andrecuellar commented 2 years ago

Still bugged also on desktop

try with my method

acwo commented 1 year ago

Still bugged, I found that's it's better to use:

swipersAll.forEach(swiper => {
    swiper.on('slideChange', function() {
        swiper.pagination.render();
    swiper.pagination.update();
    });
});

but it still don't work perfectly.

gleenk commented 1 year ago

Still bugged, I found that's it's better to use:

swipersAll.forEach(swiper => {
    swiper.on('slideChange', function() {
        swiper.pagination.render();
  swiper.pagination.update();
    });
});

but it still don't work perfectly.

It works, thank you

hanoii commented 1 year ago

This was happening to me on a project and, none of the workarounds here (for still using bullets) worked for me. As it was happening outside of iOS as well, this was easier to reproduce but I was still unable to find the culprit.

I set myself a code sandbox with a pretty simple and similar swiper code and couldn't replicate it. Then by stripping out my project part by part I finally found that this seems to be a conflict with another library: https://www.framer.com/motion

I will submit a bug report there too but I wonder if there also might be something inherent on swiper that's prone to conflicts with other libraries based on the reports of this issue. Maybe they are using other libraries that conflict with swiper.

The codesanbox is https://codesandbox.io/p/sandbox/stoic-dust-xdvrhc and you can see swiping by dragging doesn't update the bullets but the arrows do. Further more, if you swipe and it doesn't update the bullets and then use the arrows it doesn't go to the end.

If you just comment out line 20 on page.tsx swiper works normally.

markhowellsmead commented 1 year ago

Still bugged, I found that's it's better to use:

swipersAll.forEach(swiper => {
    swiper.on('slideChange', function() {
        swiper.pagination.render();
  swiper.pagination.update();
    });
});

but it still don't work perfectly.

The bug is still evident for me with Swiper 10. The code snippet above seems to work for me, thanks.

arnaudambro commented 11 months ago

it was working for me with cssMode: true, and when I set to cssMode: false (because the swipe wasn't working good with touches), then it didn't work I tried all of your solutions and, together with https://github.com/nolimits4web/swiper/issues/2915#issuecomment-601764296, this is my working config now:

new Swiper("#onboarding-swiper", {
  // Install modules
  modules: [Pagination, Mousewheel],
  speed: 500,
  initialSlide: 0,
  slidesPerView: 1,
  resistance: true,
  resistanceRatio: 0.5,
  mousewheel: {
    forceToAxis: true,
  },
  // cssMode: true,
  hashNavigation: {
    watchState: true,
  },
  pagination: {
    el: ".swiper-pagination",
    type: "bullets",
    clickable: true,
  }
});
Amadeco commented 1 month ago

I tried every solution as discussed :

The only solution worked was the proposal by @janwram (using pagination type custom - renderCustom).

Thank you for your solution, it saves me some hours of debugging.

I do not understand why this issue is closed without any commenting from the author. That is not the only one I found on the project. Lack of time or misconfiguration by ourselves ?

anhtuanlee commented 3 weeks ago

I have same problem, because i reused, and that dublicate, i delete one was fix it