ionic-team / ionic-framework

A powerful cross-platform UI toolkit for building native-quality iOS, Android, and Progressive Web Apps with HTML, CSS, and JavaScript.
https://ionicframework.com
MIT License
50.94k stars 13.52k forks source link

ion-slides does not update duplicate slides when the binding source changes #6843

Closed teledemic closed 5 years ago

teledemic commented 8 years ago

Short description of the problem:

When ion-slides is set to loop, it handles rollover from last to first / first to last slides with a duplicate of the last / first slide on either end. However, when the slides are bound with ngFor, and the binding source changes, the duplicate slides are not updated. So when you are swiping across the end, you get weird looking behavior and see old slides.

I have seen this on Ionic 2 betas 6, 7, and 8

Plunker that shows an example of your issue

http://plnkr.co/29iy5R

teledemic commented 8 years ago

May be related to #6602 and/or #6515?

Devristo commented 8 years ago

This issue also affects beta 11. In my case I was creating an infinite slider, by dynamically changing the slides of a looping <ion-slider>. Like the issue above the 'duplicate' slide was not updating accordingly.

Below the workaround I am using for now, it is not perfectly smooth, but for me it's good enough for now.

<ion-slides
    #slider
    (ionDrag)="onSlideDrag()">
....
</ion-slides>
export class Sample {
  @ViewChild('slider') slider

  onSlideDrag() {
      (<any>this.slider.getSlider()).createLoop(); // Undocumented method of the Swiper API
   }
}
carlossergiorodrigo commented 7 years ago

Hi!

This issue also do not create the binding for click events in the duplicated slide product of the loop option.

In my case, the createLoop method do not resolve the issue :(

Mridul16 commented 7 years ago

IS anyone able to resolve this issue? When loop is set to true. I move from last slide to first slide the slide is not updated as per the model.

chrisjpalmer commented 7 years ago

+1 This would be great to fix.

chrisjpalmer commented 7 years ago

Heres a really dirty hack that makes it work for me.

ionic info

cli packages: (/Users/chrispalmer/Documents/Software/CollegeOne/1app/collegeone/node_modules)

    @ionic/cli-plugin-cordova       : 1.6.2
    @ionic/cli-plugin-ionic-angular : 1.4.1
    @ionic/cli-utils                : 1.7.0
    ionic (Ionic CLI)               : 3.7.0

global packages:

    Cordova CLI : 7.0.1

local packages:

    @ionic/app-scripts : 2.0.2
    Cordova Platforms  : android 6.2.3 browser 4.1.0 ios 4.4.0
    Ionic Framework    : ionic-angular 3.5.0-201707061803

System:

    Android SDK Tools : 25.2.5
    Node              : v6.9.4
    OS                : macOS Sierra
    Xcode             : Xcode 8.3.3 Build version 8E3004b
    ios-deploy        : 1.9.0
    ios-sim           : 6.0.0
    npm               : 3.10.10

In the current version of Ionic you can't access the createLoop() function. It is unexported. What you need to do is export it.

1) I went to node_modules/ionic-angular/components/slides/swiper/swiper.js In this file i added the word export to the createLoop() method.

screen shot 2017-08-07 at 3 30 50 pm

2) Then I added the createLoop() method to the swiper.d.ts file so I wouldn't get transpiler errors:

screen shot 2017-08-07 at 3 30 58 pm

3) I added the following to my component.ts file which uses slides:

screen shot 2017-08-07 at 3 30 35 pm

I installed this event handler on the slides control:

screen shot 2017-08-07 at 3 31 33 pm

When the event handler is invoked, I call the newly exported createLoop() method.

screen shot 2017-08-07 at 3 31 23 pm

Pass your reference of the slides component (which you obtained using @ViewChild()) to the function.

Works like a charm. Love to see this integrated into the slides.update() method which already exists OR perhaps a different update method like refreshDuplicates() in order to make it possible to update the duplicate slide without upsetting anyone else who uses the update() method.

PaulliDev commented 6 years ago

Still no official fix?

dvhung95 commented 6 years ago

In html set autoplay=, loop=false (or do not initail loop because of default loop is false). Use event (ionSlideDidChange) to make slides autoplay again. If you do not deal with ionSlideDidChange, the slides will stop autoplay when coming back to the first slide. HTML: <ion-slides #slides_banner autoplay="3000" (ionSlideDidChange)="changeSlides($event)"> In typescript: @ViewChild('slides_banner') slides_banner; changeSlides(event) { this.slides_banner.startAutoplay(); }

josephilipraja commented 6 years ago

In my case, a simple solution did the trick.

My ion-slides Setup:

<ion-slides #slides *ngIf="specialEventItems && specialEventItems.length" loop dir="ltr" pager autoplay="3000" speed="600" effect="slide">
    <ion-slide *ngFor="let splEvent of specialEventItems" tappable (tap)="showEvent(splEvent.id)">
        <img [src]="splEvent.banner">
    </ion-slide>
</ion-slides>

As you can see, I have a ngFor to load slides from httpAPI. Also my ion-slides loops & autoplays with slide effect.

I had an implementation of 'Pull to Refresh' to reload Slides from httpAPI; the above code worked without issues until the data is reloaded. Few duplicate ion-slide elements were the culprit, causing bad looping.

Solution for me:

getSpecialEvents () {
    this.specialEventItems = [];  // <===== THIS DID THE TRICK!!
    this.api.get('special-events').subscribe(
        (res) => {
            this.specialEventItems = res['events'];
        }
    );
}

Simply, I rest the slides variable to empty array before fetching new data from httpAPI. I guess, the duplicated elements gets deleted once I reset the slides to an empty array.

Hope this helps someone.

shriniwasb commented 6 years ago

Hi, Instead of loop, i found another solution somewhere...

isFirstTimeLoaded: boolean = true;
    arr = [0, 1, 2];
    firstLoad = true;
    @ViewChild('slides') slides: Slides;

loadPrev() {
        console.log('Prev');
        newIndex++;
        this.arr.unshift(this.arr[0] - 1);
        this.arr.pop();

        // Workaround to make it work: breaks the animation
        this.slides.slideTo(newIndex, 0, false);

        console.log(`New status: ${this.arr}`);
    }

    loadNext() {
        if (this.firstLoad) {
            // Since the initial slide is 1, prevent the first 
            // movement to modify the slides
            this.firstLoad = false;
            return;
        }
        console.log('Next');
        let newIndex = this.slides.getActiveIndex();

        newIndex--;
        this.arr.push(this.arr[this.arr.length - 1] + 1);
        this.arr.shift();

        // Workaround to make it work: breaks the animation
        this.slides.slideTo(newIndex, 0, false);

        console.log(`New status: ${this.arr}`);
    }

<ion-slides #slides (ionSlideNextEnd)="loadNext()" (ionSlidePrevEnd)="loadPrev()" [initialSlide]="1">
        <ion-slide *ngFor="let x of arr">
        </ion-slide>
    </ion-slides>
ionitron-bot[bot] commented 5 years ago

Thanks for the issue! We have moved the source code and issues for Ionic 3 into a separate repository. I am moving this issue to the repository for Ionic 3. Please track this issue over there.

Thank you for using Ionic!

ionitron-bot[bot] commented 5 years ago

Issue moved to: https://github.com/ionic-team/ionic-v3/issues/101