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

Slides.slideTo not working when filling slides with data of promise #6703

Closed elineopsommer closed 5 years ago

elineopsommer commented 8 years ago

Short description of the problem:

After filling the slides with data of an promise, sliding to specific slide is not working. When I click on the button, then the sliding to specific slide is working. But I want to slide the slider to an specific slide by startup of the page. See plunker for example of issue. (home.html & home.ts)

What behavior are you expecting?

Relevant code:

  @ViewChild('mySlider') slider:Slides;
  private slides:JSON;

  constructor() {
        this.getSlidesOfApi().then((slides:JSON) => {
          this.slides = slides;
          this.slider.slideTo(3,0);
        });
    }

    private getSlidesOfApi():Promise<JSON>{
      return new Promise((fulfill, reject) => {
        let jsonSlides = [
          {title:"slide 1"},{title:"slide 2"},{title:"slide 3"},{title:"slide 4"},{title:"slide 5"}
        ];
        fulfill(jsonSlides);
      })
    }

    public slide(){
      this.slider.slideTo(3,0);
    }

Which Ionic Version? 2.x

Plunker that shows an example of your issue

http://plnkr.co/edit/LTGjnmJMTjqwX25xtFjV?p=preview

Run ionic info from terminal/cmd prompt: (paste output below) Your system information:

Cordova CLI: 5.4.1 Gulp version: CLI version 3.9.0 Gulp local: Local version 3.9.1 Ionic Framework Version: 2.0.0-beta.7 Ionic CLI Version: 2.0.0-beta.25 Ionic App Lib Version: 2.0.0-beta.15 ios-deploy version: Not installed ios-sim version: Not installed OS: Mac OS X El Capitan Node Version: v5.3.0 Xcode version: Xcode 7.3.1 Build version 7D1014

elineopsommer commented 8 years ago

@Ionitron It is on both the platforms: android and ios

brandyscarney commented 8 years ago

There are console errors of Cannot read property 'slideTo' of undefined. The ViewChild is set before the ngAfterViewInit callback is called so this needs to be in the ngAfterViewInit callback. Then, there is something going on with the timing that we'll have to look into. This workaround is working for me:

ngAfterViewInit() {
  this.getSlidesOfApi().then((slides:JSON) => {
    this.slides = slides;
    setTimeout(() => {
      this.slider.slideTo(3,0);
    });
  });
}

Let me know if that helps!

elineopsommer commented 8 years ago

@brandyscarney It still doesn't work if you do it with an Http request. I updated the plunk: http://plnkr.co/edit/LTGjnmJMTjqwX25xtFjV?p=preview

elineopsommer commented 8 years ago

@brandyscarney if you set the timing on the settimeout on 150 then it will work in the plunker, but not when you run it on a phone. So messing with the timeout seems not a good solution.

elineopsommer commented 8 years ago

@brandyscarney any updates on this?

elineopsommer commented 8 years ago

@jgw96 Any updates on this? I need this..

SkogDev commented 8 years ago

Any updates on this?

elineopsommer commented 8 years ago

I still got the issue..

brandyscarney commented 8 years ago

Can anyone please provide a plunker that reproduces the problem? The plunker attached is working for me.

elineopsommer commented 8 years ago

@brandyscarney It is working on the plunker, but not on a phone.

brandyscarney commented 8 years ago

@elineopsommer Ahh yeah sorry. Unfortunately I haven't had time to really look into this, but I believe it is caused by the init of the slider being wrapped in a setTimeout. There are some timing errors in slider and I believe it will require a rewrite of the component: https://github.com/driftyco/ionic/blob/master/src/components/slides/slides.ts#L396

elineopsommer commented 8 years ago

Do you have a timeline on it?

brandyscarney commented 8 years ago

Not currently. We've been holding off on making changes to the slider until we add a new gesture controller: https://github.com/driftyco/ionic/pull/7212

Then we're going to need to evaluate the slides as a whole to resolve all the underlying issues: https://github.com/driftyco/ionic/issues/6198 https://github.com/driftyco/ionic/issues/6007 https://github.com/driftyco/ionic/issues/5508 https://github.com/driftyco/ionic/issues/6301 https://github.com/driftyco/ionic/issues/6313 https://github.com/driftyco/ionic/issues/6515 https://github.com/driftyco/ionic/issues/6678 https://github.com/driftyco/ionic/issues/6843

galuszkak commented 8 years ago

@brandyscarney I see why this is failing. Can I propose alternative implementation to initialisation of Slides? Now we have this https://github.com/driftyco/ionic/blob/master/src/components/slides/slides.ts#L396 :

setTimeout(() => {
   var swiper = new Swiper(this.getNativeElement().children[0], options);
   this.slider = swiper;
}, 300);

So we actually make it initialise later for whatever good reason is for that.

What I propose is change that to make it observable:

class Slides{
  /**
   * private
   */
  slider$: BehaviorSubject<Swiper> = new BehaviorSubject(null);

  /**
   * public for dealing with async initialisation of Swiper;
   */
  getSlider$(): Observable<Swiper>{
    return this.slider$;
  }

  ngOnInit() {
    [...]
    Observable.of(options)
      .debounceTime(300)
      .map((options)=>new Swiper(this.getNativeElement().children[0], options))
      .subscribe((swiper)=>{
        this.slider = swiper;
        this.slider$.next(swiper);
      });
  }

}

This implementation solve CORE issue which is async initialisation of slider. It makes also easy for other developers to catch Swiper object after it's initialised.

galuszkak commented 8 years ago

@brandyscarney as #7212 is done will you be so kind to look on my proposal above for this issue?

rico commented 7 years ago

My turn ;-) any update on this?

I have the same problem - no problem when running in the browser, but on the phone I get ERROR: EXCEPTION: Uncaught (in promise): TypeError: undefined is not an object (evaluating 'this.slider.slideTo'). Using Ionic RC0.

wh33ler commented 7 years ago

any news here? Have the same issue and no good solution for this yet.

dallastjames commented 7 years ago

This may not be the best solution to this problem, but it works out pretty good for a temporary workaround and hopefully helps someone until we get a more permanent solution.

@ViewChild('weekSlider') weekSlider: Slides;

private _watchSlideLength():any {
        if(!this.weekSlider || this.weekSlider.length() < 1) {
            console.log('not ready');
            return setTimeout(() => {
                return this._watchSlideLength();
            }, 50);
        }
        else {
            console.log('ready', this.weekSlider.length());
            return setTimeout(() => {
                this.weekSlider.slideTo(2);
            }, 50);
        }
}

In my case, the data I'm loading is 5 weeks worth of data and so I want to slide to the middle of the five weeks that get loaded after the data gets loaded. I call this function after I get my data and it watches for the slider to be initialized and have a length of greater than 0 to know that the slider is ready. Once it has a length, the slideTo method should be available.

Like I mentioned above, it's not a great solution, but it's one that has been working for me (Android & iOS). Hope it helps someone! :)

salazarr-js commented 7 years ago

@dallastjames is there a way to implement that with an observable?

dallastjames commented 7 years ago

@slzr When I originally wrote that I couldn't find any accessible observables regarding the slider to subscribe to that would help know when the slider had loaded the slides based on the data. I know that the latest release of Ionic RC5 the slides component was refactored and rewritten and so it may have better compatibility at this point. I haven't looked at the changes much to see if there is anything new that could help refactor the above solution to use observables, but there may be. It may be worth looking at some of the new output events to see if any fire as the slides are being dynamically created.

KleinTong commented 7 years ago

i try to add import { Slides } from 'ionic-angular'; and it works. i hope it can help you.

andmar8 commented 7 years ago

I'm assuming this still hasn't really gone anywhere?

aviqbaihaqy commented 7 years ago

it work in my code place the slideTo in ionViewDidEnter function

ionViewDidEnter() {
    this.slides.slideTo(this.itemIndex, 500);
  }

check this. lifecycle view in ionic http://blog.ionic.io/navigating-lifecycle-events/

PunkHaz4rd commented 7 years ago

Still an issue, and not just on iOS

pdyraga commented 7 years ago

I was playing with various output events and couldn't find any firing at the appropriate moment. The workaround proposed by @dallastjames is still the best one available now.

andmar8 commented 7 years ago

yup, just wait until the slider length is what you would expect "then" call slider.slideTo... but there really, really, really should be some form of promise on the slider when it has updated the contained slides so you can chain a then(()=>{}).

Maybe something like slider.onSlidesChanged() ???

BalajiR commented 7 years ago

For the same scenario (slides based on data from API call), i'm able to get this slideTo works only when the slide changes are watched through ViewChildren (QueryList) as below :

// Mentioned only the lines required to keep it simple
@ViewChild(Slides) slides: Slides;
@ViewChildren(Slide) slideCollection: QueryList<Slide>;

slideIndexToMove = 2;

// Ionic lifecycle
ionViewDidLoad() {

 this.slideCollection.changes.subscribe((r) => {
    setTimeout(() => {
       this.slides.slideTo(this.slideIndexToMove, 0);
    });
 });
}
pistou commented 6 years ago

This issue is still a thing in ionic 3 👎

andmar8 commented 6 years ago

Yup, quite a few people complaining about really long terms bugs in ionic of late, but they have been busy with ionic 4, so....

As posted above, the only solution I found was using a wait loop to check for the length of slides you are expecting.... or just delaying the execution path once for an arbitrary period of time (say... 500ms) as some have suggested.

himgodfreyho commented 6 years ago

Problem still exists on latest ionic. Was debugging over and over until I found this post. @dallastjames solution saved my day!

Godbluff commented 6 years ago

I've been grappling with this issue for a while. I have a set of sliders that are being shown and hidden by an ngIf. Without a timeout long enough the slides consistently return a length of undefined, which of course wrecks anything you're trying to in addition to showing the slides, such as moving to a specific slide. So for me the solution of waiting for the length on the slides was not working.

I did discover that i could use the (ionSlideReachStart) on the ion-slides element as a safe indicator that the slides were ready. I use this event as a staring point. In my case I have a set Timeout loop checking a boolean that is set to true by the ionSlideReachStart. Obviously there's more happening when hiding the slider etc, but for me this was a good place to start.

I realize that for anyone using this event for other functionality on the slides might run into some other issues, but hopefully someone might find this solution useful. Still a hack, so I hope a more specific envent might be available in the future.

ap1969 commented 6 years ago

I got it working with the solution by @baihaqyaviq - thanks so much!

Solution at https://github.com/ionic-team/ionic/issues/6703#issuecomment-292721464

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

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/99