Don't forget to clean up subscriptions
authorChocobozzz <me@florianbigard.com>
Mon, 19 Mar 2018 17:00:31 +0000 (18:00 +0100)
committerChocobozzz <me@florianbigard.com>
Mon, 19 Mar 2018 17:00:31 +0000 (18:00 +0100)
client/src/app/account/account-videos/account-videos.component.ts
client/src/app/shared/video/abstract-video-list.ts
client/src/app/shared/video/infinite-scroller.directive.ts
client/src/app/videos/video-list/video-local.component.ts
client/src/app/videos/video-list/video-recently-added.component.ts
client/src/app/videos/video-list/video-search.component.ts
client/src/app/videos/video-list/video-trending.component.ts

index a286bad1c7432ca7cdf31a0339fcf96103dc3214..cd0f8e752dd6024827e348b0c2e16373073ac19c 100644 (file)
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core'
+import { Component, OnInit, OnDestroy } from '@angular/core'
 import { ActivatedRoute, Router } from '@angular/router'
 import { immutableAssign } from '@app/shared/misc/utils'
 import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
@@ -17,18 +17,19 @@ import { VideoService } from '../../shared/video/video.service'
   templateUrl: './account-videos.component.html',
   styleUrls: [ './account-videos.component.scss' ]
 })
-export class AccountVideosComponent extends AbstractVideoList implements OnInit {
+export class AccountVideosComponent extends AbstractVideoList implements OnInit, OnDestroy {
   titlePage = 'My videos'
   currentRoute = '/account/videos'
   checkedVideos: { [ id: number ]: boolean } = {}
-  videoHeight = 155
-  videoWidth = -1
   pagination: ComponentPagination = {
     currentPage: 1,
     itemsPerPage: 10,
     totalItems: null
   }
 
+  protected baseVideoWidth = -1
+  protected baseVideoHeight = 155
+
   constructor (protected router: Router,
                protected route: ActivatedRoute,
                protected authService: AuthService,
@@ -42,6 +43,10 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
     super.ngOnInit()
   }
 
+  ngOnDestroy () {
+    super.ngOnDestroy()
+  }
+
   abortSelectionMode () {
     this.checkedVideos = {}
   }
index 570aaae9d8e2edeed6da9bf817d25cea89a32f09..4a220c93d246ce0c2d066686ae59c421f62e72b1 100644 (file)
@@ -1,4 +1,4 @@
-import { ElementRef, OnInit, ViewChild } from '@angular/core'
+import { ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core'
 import { ActivatedRoute, Router } from '@angular/router'
 import { isInMobileView } from '@app/shared/misc/utils'
 import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive'
@@ -6,12 +6,13 @@ import { NotificationsService } from 'angular2-notifications'
 import 'rxjs/add/operator/debounceTime'
 import { Observable } from 'rxjs/Observable'
 import { fromEvent } from 'rxjs/observable/fromEvent'
+import { Subscription } from 'rxjs/Subscription'
 import { AuthService } from '../../core/auth'
 import { ComponentPagination } from '../rest/component-pagination.model'
 import { SortField } from './sort-field.type'
 import { Video } from './video.model'
 
-export abstract class AbstractVideoList implements OnInit {
+export abstract class AbstractVideoList implements OnInit, OnDestroy {
   private static LINES_PER_PAGE = 3
 
   @ViewChild('videoElement') videosElement: ElementRef
@@ -30,6 +31,9 @@ export abstract class AbstractVideoList implements OnInit {
   videoHeight: number
   videoPages: Video[][] = []
 
+  protected baseVideoWidth = 215
+  protected baseVideoHeight = 230
+
   protected abstract notificationsService: NotificationsService
   protected abstract authService: AuthService
   protected abstract router: Router
@@ -40,6 +44,8 @@ export abstract class AbstractVideoList implements OnInit {
   protected loadedPages: { [ id: number ]: Video[] } = {}
   protected otherRouteParams = {}
 
+  private resizeSubscription: Subscription
+
   abstract getVideosObservable (page: number): Observable<{ videos: Video[], totalVideos: number}>
 
   get user () {
@@ -51,7 +57,7 @@ export abstract class AbstractVideoList implements OnInit {
     const routeParams = this.route.snapshot.params
     this.loadRouteParams(routeParams)
 
-    fromEvent(window, 'resize')
+    this.resizeSubscription = fromEvent(window, 'resize')
       .debounceTime(500)
       .subscribe(() => this.calcPageSizes())
 
@@ -59,6 +65,10 @@ export abstract class AbstractVideoList implements OnInit {
     if (this.loadOnInit === true) this.loadMoreVideos(this.pagination.currentPage)
   }
 
+  ngOnDestroy () {
+    if (this.resizeSubscription) this.resizeSubscription.unsubscribe()
+  }
+
   onNearOfTop () {
     this.previousPage()
   }
@@ -168,15 +178,15 @@ export abstract class AbstractVideoList implements OnInit {
   }
 
   private calcPageSizes () {
-    if (isInMobileView()) {
+    if (isInMobileView() || this.baseVideoWidth === -1) {
       this.pagination.itemsPerPage = 5
 
       // Video takes all the width
       this.videoWidth = -1
       this.pageHeight = this.pagination.itemsPerPage * this.videoHeight
     } else {
-      this.videoWidth = 215
-      this.videoHeight = 230
+      this.videoWidth = this.baseVideoWidth
+      this.videoHeight = this.baseVideoHeight
 
       const videosWidth = this.videosElement.nativeElement.offsetWidth
       this.pagination.itemsPerPage = Math.floor(videosWidth / this.videoWidth) * AbstractVideoList.LINES_PER_PAGE
@@ -194,7 +204,12 @@ export abstract class AbstractVideoList implements OnInit {
       i++
     }
 
-    this.buildVideoPages()
+    // Re fetch the last page
+    if (videos.length !== 0) {
+      this.loadMoreVideos(i)
+    } else {
+      this.buildVideoPages()
+    }
 
     console.log('Rebuilt pages with %s elements per page.', this.pagination.itemsPerPage)
   }
index e0f9f4f836fc74b89ec96adc963bc6e44e2bda33..e2730423f38e9fd19d17085e6a3396897ea8b4e8 100644 (file)
@@ -1,18 +1,19 @@
-import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core'
+import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'
 import 'rxjs/add/operator/debounceTime'
 import 'rxjs/add/operator/distinct'
 import 'rxjs/add/operator/distinctUntilChanged'
 import 'rxjs/add/operator/filter'
 import 'rxjs/add/operator/map'
+import 'rxjs/add/operator/share'
 import 'rxjs/add/operator/startWith'
 import 'rxjs/add/operator/throttleTime'
 import { fromEvent } from 'rxjs/observable/fromEvent'
-import 'rxjs/add/operator/share'
+import { Subscription } from 'rxjs/Subscription'
 
 @Directive({
   selector: '[myInfiniteScroller]'
 })
-export class InfiniteScrollerDirective implements OnInit {
+export class InfiniteScrollerDirective implements OnInit, OnDestroy {
   private static PAGE_VIEW_TOP_MARGIN = 500
 
   @Input() containerHeight: number
@@ -27,6 +28,9 @@ export class InfiniteScrollerDirective implements OnInit {
   private decimalLimit = 0
   private lastCurrentBottom = -1
   private lastCurrentTop = 0
+  private scrollDownSub: Subscription
+  private scrollUpSub: Subscription
+  private pageChangeSub: Subscription
 
   constructor () {
     this.decimalLimit = this.percentLimit / 100
@@ -36,6 +40,12 @@ export class InfiniteScrollerDirective implements OnInit {
     if (this.autoLoading === true) return this.initialize()
   }
 
+  ngOnDestroy () {
+    if (this.scrollDownSub) this.scrollDownSub.unsubscribe()
+    if (this.scrollUpSub) this.scrollUpSub.unsubscribe()
+    if (this.pageChangeSub) this.pageChangeSub.unsubscribe()
+  }
+
   initialize () {
     // Emit the last value
     const throttleOptions = { leading: true, trailing: true }
@@ -48,7 +58,7 @@ export class InfiniteScrollerDirective implements OnInit {
       .share()
 
     // Scroll Down
-    scrollObservable
+    this.scrollDownSub = scrollObservable
       // Check we scroll down
       .filter(({ current }) => {
         const res = this.lastCurrentBottom < current
@@ -60,7 +70,7 @@ export class InfiniteScrollerDirective implements OnInit {
       .subscribe(() => this.nearOfBottom.emit())
 
     // Scroll up
-    scrollObservable
+    this.scrollUpSub = scrollObservable
       // Check we scroll up
       .filter(({ current }) => {
         const res = this.lastCurrentTop > current
@@ -74,7 +84,7 @@ export class InfiniteScrollerDirective implements OnInit {
       .subscribe(() => this.nearOfTop.emit())
 
     // Page change
-    scrollObservable
+    this.pageChangeSub = scrollObservable
       .distinct()
       .map(({ current }) => this.calculateCurrentPage(current))
       .distinctUntilChanged()
index 8cac2c12c2a052e1ba3d7535b647a6df3abb37a9..8f9d50a7bda27d3228370007b2dd242e5824115c 100644 (file)
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core'
+import { Component, OnDestroy, OnInit } from '@angular/core'
 import { ActivatedRoute, Router } from '@angular/router'
 import { immutableAssign } from '@app/shared/misc/utils'
 import { NotificationsService } from 'angular2-notifications'
@@ -12,7 +12,7 @@ import { VideoService } from '../../shared/video/video.service'
   styleUrls: [ '../../shared/video/abstract-video-list.scss' ],
   templateUrl: '../../shared/video/abstract-video-list.html'
 })
-export class VideoLocalComponent extends AbstractVideoList implements OnInit {
+export class VideoLocalComponent extends AbstractVideoList implements OnInit, OnDestroy {
   titlePage = 'Local videos'
   currentRoute = '/videos/local'
   sort = '-createdAt' as SortField
@@ -29,6 +29,10 @@ export class VideoLocalComponent extends AbstractVideoList implements OnInit {
     super.ngOnInit()
   }
 
+  ngOnDestroy () {
+    super.ngOnDestroy()
+  }
+
   getVideosObservable (page: number) {
     const newPagination = immutableAssign(this.pagination, { currentPage: page })
 
index f150e38dabe2b3369f37779977abc14bafa9b548..1cecd14a0c5f0af92f31ded15d8f541e02f8bbf4 100644 (file)
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core'
+import { Component, OnDestroy, OnInit } from '@angular/core'
 import { ActivatedRoute, Router } from '@angular/router'
 import { immutableAssign } from '@app/shared/misc/utils'
 import { NotificationsService } from 'angular2-notifications'
@@ -12,7 +12,7 @@ import { VideoService } from '../../shared/video/video.service'
   styleUrls: [ '../../shared/video/abstract-video-list.scss' ],
   templateUrl: '../../shared/video/abstract-video-list.html'
 })
-export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit {
+export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy {
   titlePage = 'Recently added'
   currentRoute = '/videos/recently-added'
   sort: SortField = '-createdAt'
@@ -29,6 +29,10 @@ export class VideoRecentlyAddedComponent extends AbstractVideoList implements On
     super.ngOnInit()
   }
 
+  ngOnDestroy () {
+    super.ngOnDestroy()
+  }
+
   getVideosObservable (page: number) {
     const newPagination = immutableAssign(this.pagination, { currentPage: page })
 
index 241b97bc7e1aa75c288dfe904114a8d0f0006c65..788797a4cf6cfcaf9f10407ed32c3159f8792a94 100644 (file)
@@ -47,9 +47,9 @@ export class VideoSearchComponent extends AbstractVideoList implements OnInit, O
   }
 
   ngOnDestroy () {
-    if (this.subActivatedRoute) {
-      this.subActivatedRoute.unsubscribe()
-    }
+    super.ngOnDestroy()
+
+    if (this.subActivatedRoute) this.subActivatedRoute.unsubscribe()
   }
 
   getVideosObservable (page: number) {
index a42457273125d8c790086767d338d4436dbde9c3..1dd1ad23bcef353c583254b903f9633be6c80b3b 100644 (file)
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core'
+import { Component, OnDestroy, OnInit } from '@angular/core'
 import { ActivatedRoute, Router } from '@angular/router'
 import { immutableAssign } from '@app/shared/misc/utils'
 import { NotificationsService } from 'angular2-notifications'
@@ -12,7 +12,7 @@ import { VideoService } from '../../shared/video/video.service'
   styleUrls: [ '../../shared/video/abstract-video-list.scss' ],
   templateUrl: '../../shared/video/abstract-video-list.html'
 })
-export class VideoTrendingComponent extends AbstractVideoList implements OnInit {
+export class VideoTrendingComponent extends AbstractVideoList implements OnInit, OnDestroy {
   titlePage = 'Trending'
   currentRoute = '/videos/trending'
   defaultSort: SortField = '-views'
@@ -29,6 +29,10 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit
     super.ngOnInit()
   }
 
+  ngOnDestroy () {
+    super.ngOnDestroy()
+  }
+
   getVideosObservable (page: number) {
     const newPagination = immutableAssign(this.pagination, { currentPage: page })
     return this.videoService.getVideos(newPagination, this.sort)