Reputation: 6117
I want to make a "continuous" slider in Ionic 3.
I use 3 slides and update the content on each slide action. This works, though when swiping the last slide and looping back to the first, the content of the newly shown slide is not correct: all static data is shown, but all dynamic (bound) data is not shown. You need to initiate a new swipe action (just drag the page a tiny bit) to get the data shown.
See this plunker as an example of the issue:
https://plnkr.co/edit/YC9xiwH9hVtAmhUTO2Oc?p=preview
This is the view:
<ion-content padding>
slides:
<ion-slides loop="true" (ionSlideDidChange)="slideChanged($event)">
<ion-slide>
0 {{data[0]?.title}}
</ion-slide>
<ion-slide>
1 {{data[1]?.title}}
</ion-slide>
<ion-slide>
2 {{data[2]?.title}}
</ion-slide>
</ion-slides>
</ion-content>
This is the controller:
import { Component } from '@angular/core'; import { NavController } from 'ionic-angular';
@Component({
selector: 'page-home',
templateUrl: 'app/home.page.html'
})
export class HomePage {
appName = 'Ionic App';
slides: Slides;
public data: MonthViewData[] = [];
public date = new Date(Date.now());
monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
];
constructor() {
this.data.push({title:'t0'});
this.data.push({title:'t1'});
this.data.push({title:'t2'});
}
slideChanged(slides: Slides) {
this.slides = slides;
return new Promise((resolve, reject) => {
let scrollToNext = this.slides.getActiveIndex() > this.slides.getPreviousIndex();
console.log(this.slides.getActiveIndex(), this.slides.getPreviousIndex());
let currentSlideIndex: number = this.slides.getActiveIndex() - 1;
if (currentSlideIndex > 2) {
currentSlideIndex = 0;
}
if (currentSlideIndex < 0) {
currentSlideIndex = 2;
}
let previousSlideIndex = currentSlideIndex - 1;
let nextSlideIndex = currentSlideIndex + 1;
if (previousSlideIndex < 0) {
previousSlideIndex = 2;
}
if (nextSlideIndex > 2) {
nextSlideIndex = 0;
}
if (this.slides.getActiveIndex() == 1 && this.slides.getPreviousIndex() == 0) {
this.date = new Date(Date.now());
} else {
if (scrollToNext) {
this.date.setMonth(this.date.getMonth() + 1);
} else {
this.date.setMonth(this.date.getMonth() - 1);
}
}
console.log('active month', this.date);
console.log('indexes', previousSlideIndex, '->', currentSlideIndex, '->', nextSlideIndex);
this.data[currentSlideIndex].title = this.monthNames[this.date.getMonth()] + ' ' + this.date.getFullYear();
this.data[previousSlideIndex].title = this.monthNames[this.date.getMonth() - 1] + ' ' + this.date.getFullYear();
this.data[nextSlideIndex].title = this.monthNames[this.date.getMonth() + 1] + ' ' + this.date.getFullYear();
})
}
}
How can I get this right?
Thanks!
Upvotes: 3
Views: 3471
Reputation: 1
Try this code. Use realIndex of slides
This is View
<ion-slides loop="true" (ionSlideDidChange)="slideChanged($event)">
<ion-slide *ngFor="let item of items">Slide {{newval}}
<ion-list>
<ion-item *ngFor="let item of items">
Slide {{newval}} not changing
</ion-item>
</ion-list>
</ion-slide>
</ion-slides>
</ion-content>
Controller Part
export class HomePage {
items: number[] = [0,1,2,3,4,5,6,7,8,9];
newval : any;
appName = 'Ionic App';
constructor(public navController: NavController) { }
slideChanged(event) {
this.newval = event.realIndex;
}
}
Refer this for example
http://next.plnkr.co/edit/6o5cy8gClpBJv6iG?preview
Upvotes: 0
Reputation: 8031
If you give a look in the browser inspector, you will see that the ones that don't work are the first slide after you loop from the last, or the last slide after you loop from the first (in the inverse direction), and both of them has the class swiper-slide-duplicate
, that is, they are duplicates, and the ones that work are not duplicates.
Sometimes, while you are changing the slide, you can see, during a brief moment, the correct value, because the duplicate is changed with the original.
It seems ionic
tries to duplicate the slides, but the duplication can give unexpected errors when using angular bindings and change detection, making that it doesn't work at all.
At first, (in my case, not the one in the plunker), I thought it was change detection that was not triggering in my component and tried all sorts of stuff like ngZone.run()
, cd.markForChanges()
, cd.detectChanges()
and so on...
In my opinion, the current "fix" is to not use loop
when you want dynamic change detection (the items can change), when the detection must happen inside the slide.
In my case, I disabled loop
and use autoPlay
, then I just call slides.startAutoplay()
when the slide changes.
In your case it would inside slideChanged(slides: Slides) { ... slides.startAutoplay(); }
This won't solve your problem, tough, because in your code you want to show the next month in each slide and make it look like having infinite slides (always changing the next slide as you loop). Also, it seems you want the change to be manual (by the user).
What I advise you is to look for other approaches because I don't know when it will be solved.
There are several issues about that opened:
https://github.com/ionic-team/ionic-v1/issues/129 (it's in v1, but the problem is the same. The original issue is https://github.com/ionic-team/ionic/issues/6602, created in 2016-05-21, almost 2 years ago)
https://github.com/ionic-team/ionic/issues/6515
https://github.com/ionic-team/ionic/issues/6843
https://github.com/ionic-team/ionic/issues/10890
https://github.com/ionic-team/ionic/issues/13582
(and probably more...)
Perhaps in Ionic4
that will be solved, but I think not (at least not for now), so I advise to try another approach (instead of ion-slides
) in your case.
Upvotes: 4