Linkd-Inc / ngx-slideshow

An Agular 2+ slideshow component
5 stars 0 forks source link

Handle delayed inputs without throwing errors #13

Open irfan-stranger opened 6 years ago

irfan-stranger commented 6 years ago

Hi

It's working fine with static data but when I add loop in slideshow stopped working. And on click on next previous arrow it through error.

My code

<div class="ngx_carousel"><span (click)="carousel.left()">Left</span><ngx-slideshow #carousel [cards]="1" [cardSize]="'100%'" [padding]="'14px'" *ngIf="SliderLangData?.pageProperties?.home?.slider"><li *ngFor="let slider of SliderLangData?.pageProperties?.home?.slider"><div class="row"><div *ngIf="slider?.text" [innerHTML]="slider.text"></div><div class="col-md-6"><img *ngIf="slider.imageUri" src="{{slider.imageUri}}" title="Qoin pro"></div></div></li></ngx-slideshow> <span (click)=carousel.right()">Right</span></div>

Error

ERROR TypeError: Cannot read property 'left' of undefined at Object.eval [as handleEvent] (HomeComponent.html:216) at handleEvent (core.js:13589) at callWithDebugContext (core.js:15098) at Object.debugHandleEvent [as handleEvent] (core.js:14685) at dispatchEvent (core.js:10004) at eval (core.js:10629) at HTMLParagraphElement.eval (platform-browser.js:2628) at ZoneDelegate.invokeTask (zone.js:421) at Object.onInvokeTask (core.js:4751) at ZoneDelegate.invokeTask (zone.js:420)

On More thing I want to know can I make it auto play? Rest you done a great job.

crutchcorn commented 6 years ago

I recently had the same issue in a project we're working on.

I'll likely be working on ngx-slideshow today to fix this and a few other bugs that we've discovered recently, but in the meantime a workaround that we're using is as follows:

Add a boolean that's added after the data is retreived, oftentimes at the end of a subscription. setTimeout(() => this.data = true, 0); (remember to either patch RxJS or add manual change detection if it's inside a subscription)

And one after ngAfterViewInit.

Then, change your carousels to wait for both booleans to be true: <span *ngIf="data && viewInit" (click)=carousel.right()">Right</span>

Is it hacky? Yes. Does it work for now? Yes. Are bananas tasty? Debatable. Am I going to fix it? Yes.

Thanks for contributing! :)

crutchcorn commented 6 years ago

Oh, I've seemed to miss the autoplay feature request - you can absolutely do this using an interval Observable like so:

import {Component, OnInit, ViewChild, HostListener, ViewChild} from '@angular/core';
import {NgxSlideshowComponent} from 'ngx-slideshow';
import {interval} from "rxjs";

export class Component implements OnInit {
    @ViewChild(NgxSlideshowComponent) slideshow: NgxSlideshowComponent;

    ngOnInit {
        // 2000ms = 2s
        interval(2000).subscribe(_ => this.slideshow.left());
    }
}

You can even do something like:

import { Component, OnInit, AfterViewInit } from '@angular/core';
import { Subject, timer, interval } from "rxjs";
import { switchMap } from "rxjs/operators";

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, AfterViewInit {
  @ViewChild(NgxSlideshowComponent) slideshow: NgxSlideshowComponent;
  subscription = new Subject();

  ngOnInit() {
    this.subscription
      .pipe(
          switchMap((time: number) => timer(time ? time : 5000))),
          switchMap(() => interval(2000))
      )
      .subscribe(_ => this.slideshow.left());
  }

  ngAfterViewInit() {
    this.subscription.next(0);
  }

  @HostListener('click')
  onClick() {
    this.subscription.next();
  }
}

And then call test() on the button click in order to have it pause for 5 seconds if the user tries to take over and click around themselves before starting to rotate again with 2 second intervals.

I've been considering adding this feature in, and I think I will, but for now the code I've linked should more than work out for you :) `