Ionic-framework: bug: Ionic2 ion-slides not properly working with *ngFor

Created on 12 May 2016  路  27Comments  路  Source: ionic-team/ionic-framework

Type: bug

Ionic Version: 2.x

Platform: all

Hey Ionic 2 team,

Ionic 2 ion-slides component seems to be working properly when ion-slide are either hardcoded into the template or when they are created with a ngFor iterating over an array that is not empty/not modified.
If the ngFor is first iterating over an empty array and then the array is modified, the slides seems to be broken (in particular, looping is not working properly).

This bug can maybe be generalised to any ion-slides that are dynamically added/removed after the first creation of the ion-slides but I have not tested this.

To reproduce the bug, clone, install and launch the sample app of this repo: https://github.com/4ian/ionic2-slides-test

Click on the button to fill the array used to generate the slides. The second slider won't work properly. The first slider will be working but I've used a workaround: the slider is not created when the array is empty.

v3

Most helpful comment

+1

All 27 comments

Thank you for the workaround - helped a ton

What was the workaround here?

In my case, I delayed the creation of the slider until I have all the data needed (a simple *ngIf="items.length" to ensure that the items array was filled with fetched data).
See: https://github.com/4ian/ionic2-slides-test/blob/master/app/pages/hello-ionic/hello-ionic.html

I found I was also having problems on update, so I am briefly (10ms) setting the binding source to empty whenever it changes, so the ngIf deletes and recreates the slides rather than updating them incorrectly.

Thank's

Really workarounds !!
Thanks.

I had to replace <ion-slide-box> with <ion-slides> to get it working.

On the swipper api you can see what you could put in the slide options.
http://idangero.us/swiper/api/#.WIandPHhCkA

eg ###(onReachEnd):
mySlideOptions = { pager:true, paginationClickable: true, onReachEnd : function(){ console.log("end"); this.showButton = true; } };

in the view you put the options:
<ion-slides [options]="mySlideOptions">

Voila

@t1gu1 It seems ionic guys are rewriting slides component.

how to made slide dinamic from database with ionic 2 ?

Two thing is really important when you are using ionic, and develop for mobile.

1, Try out your stuff without inspector window also on Chrome.
2, Instead of canvas use svg, as it's horrible performance wise. Now my virtual scrolling started to work smoothly - there are lot's of component which are not enough flexible, or just making me sad. (ng-lazyload-image) - it's a very heavy stuff, ionic one is not working. simply use ... 4-5 times faster.

P.s.:
ion-slide is making a mysterious 2 additional slides on the fly, which is very sensitive when the data is dynamic.

+1


=> Can't bind to 'options' since it isn't a known property of 'ion-slides'

loop breaks after ion-slices dynamic update.
template:

<ion-slides pager [autoplay]="2000" [loop]="true" #slides>
      <ion-slide *ngFor="#item of items">      
          {{ item}}
      </ion-slide>
</ion-slides>

component:

items=[ 1, 2, 3]; // works fine so far
@ViewChild('slides') slides: Slides;
constructor(private http: Http) {
}

ionViewDidLoad() {
      this.http.get('...').then(r=>{
            this.items=r;  // e.g. [4, 5, 6] 
            setTimeout(()=>{ // delay to update
                  this.slides.update(); // loop broken here.
            }, 500);
      });
}

By the way, it works fine with ionic 1.

did you manage to fix this issue? I'm facing similar issue when I try to specify an initial slide having [hidden] active.

SlideTo also doesn't work

I made the same kinda workaround, something like what has been already posted here.

  1. I put *ngIf="!isUpdatingSlides" on ion-slides element,
  2. And then on ts file I made a variable named isUpdatingSlides: boolean = false;
  3. And after I'm done changing slides I do this
setTimeout(() => {
    this.updatingSlides = true;
    setTimeout(() => {
        this.updatingSlides = false;
    }, 10);
}, 10);

The time outs here make sure that element has been done changing and slides already updated so we don't get any more issues (I've encounter some).
This will recreate the element but however on every update you will encounter a disappearance for more than 50ms and even some funny temporary behaviors but the good thing is that it works and it gives the feelings of something changed!! It's good when you're gonna put some dummy contents or pre-cached contents before getting actual values from server and changing it or change it with every update user might want to see.

I solve it with dirty way for the dynamic slides autoplay.
Ionic autoplay options for dynamic slides get the error
so I import the following library and solve it.

import { Observable } from "rxjs/Rx";

Add the following line,
in the

constructor(){
**Observable.interval(5000).subscribe(() => {
if(this.slides.isEnd())
this.slides.slideTo(0,1000);
else
this.slides.slideNext(1000);

      });**

}

+1

+1

+1

I have a component inside of a slider tag inside of a page with an *ngFor which does work the first time i route to the page with setRoot(). The 2. time it does not work so now i have to spend a lot of time to write my own hack on top of ionic.

similar: https://stackoverflow.com/questions/38552261/ionic2-slider-is-not-working-with-ngfor-angular2

After a lot of painful research I found solution. In my case I use several slides with list of items (custom component) on each of them with infinite scroll. Here is info, that can be helpful for other developers:

  1. To update ngFor list, that located inside slide you can add pipe that takes listChanged string argument and always return list
    public transform(items: Array<any>, listChanged: string): Array<any> {
        return items;
    }

And in your component define public listChanged: string; and change it to new value every time when list updated

this.listChanged = Math.random().toString(16).slice(2);
  1. Note, that when you add some items in list, slide height will not change automatically and you need to change it manually. This comment can be helpful. In my case I call "slideDidChange(); slideWillChange();" on each infinite scroll calback

  2. Unfortunately infinite scroll will not disappear manually inside slides. But you can hide it at all by css and it will still work

<ion-infinite-scroll class="component-infinite-scroll" ...

.component-infinite-scroll {
    height: 0;
    overflow: hidden;
}
  1. When you scroll current visible slide - all hidden slides will be scrolled too, and infinite scroll callback will be fired as many times as number of slides with infinite scroll. So you need to add unique id for each slide and check it in infinite scroll callback. Same logic will happens with slide height from item 2 and without unique id checking on first load current slide height will be set as height for last available slide (it will be initialized last and rewrite current slide height)

Note: beware of side effects. I can't guarantee that this hack will work in all possible cases. I'm not sure that this can be used in production.

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.

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!

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!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

brandyscarney picture brandyscarney  路  3Comments

MrBokeh picture MrBokeh  路  3Comments

alan-agius4 picture alan-agius4  路  3Comments

brandyscarney picture brandyscarney  路  3Comments

Nick-The-Uncharted picture Nick-The-Uncharted  路  3Comments