取消订阅TimerObservable不会停止执行订阅回调

时间:2018-07-12 08:16:32

标签: angular subscriptions

我有一个显示图像网格的Angular(不是js)应用程序。该网格非常大,因此会自动滚动用户浏览器窗口,并在一定时间间隔内随机选择并显示其中一张图像(使用灯箱)。在大多数情况下,这一切都很好。

但是,在某些交互过程中,例如当用户手动取消选择显示的图像时,或者当用户离开“视图”页面导航时,很明显,TimerObservable的运行自动滚动和自动选择不会被破坏。

这会导致2种​​有害的副作用;首先,即使在其他不适合滚动的页面上(这些其他组件甚至都没有自动滚动代码!),浏览器窗口仍会继续向上/向下滚动。其次,滚动速度变成了两倍,就像已经创建了两个TimerObservable一样,并且都在滚动文档窗口。

这是我的组件代码(删除了无关的内容):

您可以在此处看到我创建了2个Subscription变量来保存在StartAutoScroll()StartAutoSelector()函数中创建的订阅。然后,我使用StopUI()StartUI()函数停止/取消订阅/销毁这些订阅,但是正如我之前所说,这不会总是发生,nudge()&即使我离开该组件(有时是有时)或自己手动取消选择灯箱,仍会调用focusTile()函数。

import { Component, OnInit, ViewEncapsulation} from '@angular/core';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
import { switchMap } from 'rxjs/operators';
import { TimerObservable } from 'rxjs/observable/TimerObservable';
import { TileViewService } from '../services/tile-view.service';
import { TileView } from '../models/TileView';
import { Lightbox, LIGHTBOX_EVENT, LightboxEvent } from 'ngx-lightbox';
import { WindowRefService } from '../services/window-ref.service';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-tile-view',
  templateUrl: './tile-view.component.html',
  styleUrls: ['./tile-view.component.scss'],
  encapsulation: ViewEncapsulation.None
})
export class TileViewComponent implements OnInit {

  // These are the subscriptions causing issues
  public isAutoScrolling : Boolean = true;
  private autoScroller: Subscription;

  public isAutoSelecting : Boolean = true;
  private autoSelector: Subscription;

  tileView: TileView;
  private tileAlbum: Array<any> = [];

  public isFrozen : Boolean;



  private nudgeValue = 1;

  public focusTileDelay = 8000;
  public focusTileDuration = 5000;

  private lightboxSubscription : Subscription;

  private albumIndicies: Array<number> = [];

  constructor(
    private route: ActivatedRoute,
    private router: Router,
    private tileService: TileViewService,
    private windowRef: WindowRefService,
    private lightbox: Lightbox,
    private lightboxEvent: LightboxEvent
  ) { }

  ngOnDestroy() {
    console.info("tile-view destroyed!");
    this.stopUI();
  }
  ngOnInit() {
    var result = this.route.paramMap.pipe(
      switchMap((params: ParamMap) =>
        this.tileService.getTileById(params.get('id'))
      )
    ).subscribe((response) => {
      this.startUI();
    });
  }

  public stopUI(){
    this.stopAutoScroll();
    this.stopTileSelector();
  }
  public startUI(){
    if(this.isAutoScrolling){
      this.startAutoScroll();
    }
    else{
      this.stopAutoScroll();
    }
    if(this.isAutoSelecting){
      this.startTileSelector();
    }
    else{
      this.stopTileSelector();
    }
  }

  private startAutoScroll() {
    this.autoScroller = TimerObservable.create(0, 75).subscribe(x => {
      this.nudge();
    });
    console.debug("STARTING document scroll", this.autoScroller);
  }
  private stopAutoScroll(){
    this.autoScroller.unsubscribe();
    console.debug("STOPPING document scroll", this.autoScroller);
  }
  private startTileSelector() {
    this.autoSelector = TimerObservable.create(this.focusTileDelay, this.focusTileDuration).subscribe(x => {
      this.focusNextTile();
    });
    console.debug("STARTING tile selection", this.autoSelector);
  }
  private stopTileSelector(){
    this.autoSelector.unsubscribe();
    console.info("STOPPING tile selection", this.autoSelector);
  }


   /**
   * Destroys any existing instances of a lightbox display and shows
   * a new lightbox element for the specific album item.
   * @param index The item-position in the album to display
   */
  private focusTile(index: number): void {
    console.info("Focusing on tile #" + index);

    // Stop scrolling / selecting while we focus this tile
    this.stopUI();

    // Subscribe to events that this lightbox may emit
    this.lightboxSubscription = this.lightboxEvent.lightboxEvent$.subscribe(event => this.OnLightboxReceivedEvent(event));

    // Actually display lightbox for selected focus
    this.lightbox.open(this.tileAlbum, index, {centerVertically: true});

    // If the tile isnt frozen, automatically de-select it after the standard viewing-duration
    if(!this.isFrozen){
      setTimeout(() =>{
        this.unfocusCurrentTile();
      }, 
      this.focusTileDuration);
    }

  }

  /**
   * Removes any existing lightbox instances, re-starts UI
   */
  private unfocusCurrentTile(){

    this.stopUI();

    var overlays = document.getElementsByClassName('lightboxOverlay');
    var lightboxes = document.getElementsByClassName('lightbox');

    for(var i = 0; i < overlays.length; i++){
      overlays[i].remove();
    }
    for(var i = 0; i < lightboxes.length; i++){
      lightboxes[i].remove();
    }

    this.startUI();
  }


  private nudge() {
    if ((this.windowRef.nativeWindow.innerHeight + this.windowRef.nativeWindow.scrollY) >= document.body.offsetHeight) {
      this.nudgeValue = -1;
    }
    else if (this.windowRef.nativeWindow.scrollY == 0) {
      this.nudgeValue = 1;
    }

    this.windowRef.nativeWindow.scrollTo(
      0,
      this.windowRef.nativeWindow.scrollY + this.nudgeValue
    );
  }
}

0 个答案:

没有答案