Rewrite infinite scroll

pull/292/head
Chocobozzz 2018-02-13 14:11:05 +01:00
parent 29c6b82944
commit 0cd4344f3c
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
15 changed files with 245 additions and 119 deletions

View File

@ -61,7 +61,6 @@
"ngx-bootstrap": "2.0.2", "ngx-bootstrap": "2.0.2",
"ngx-chips": "1.6.3", "ngx-chips": "1.6.3",
"ngx-clipboard": "9.0.1", "ngx-clipboard": "9.0.1",
"ngx-infinite-scroll": "0.7.2",
"ngx-pipes": "^2.0.5", "ngx-pipes": "^2.0.5",
"node-sass": "^4.1.1", "node-sass": "^4.1.1",
"npm-font-source-sans-pro": "^1.0.2", "npm-font-source-sans-pro": "^1.0.2",

View File

@ -1,44 +1,44 @@
<div *ngIf="pagination.totalItems === 0">No results.</div> <div *ngIf="pagination.totalItems === 0">No results.</div>
<div <div
class="videos" myInfiniteScroller
infiniteScroll [pageHeight]="pageHeight"
[infiniteScrollDistance]="0.5" (nearOfTop)="onNearOfTop()" (nearOfBottom)="onNearOfBottom()" (pageChanged)="onPageChanged($event)"
[infiniteScrollUpDistance]="1.5" class="videos" #videoElement
(scrolled)="onNearOfBottom()"
(scrolledUp)="onNearOfTop()"
> >
<div class="video" *ngFor="let video of videos; let i = index"> <div *ngFor="let videos of videoPages; let i = index" class="videos-page">
<div class="checkbox-container"> <div class="video" *ngFor="let video of videos; let j = index">
<input [id]="'video-check-' + i" type="checkbox" [(ngModel)]="checkedVideos[video.id]" /> <div class="checkbox-container">
<label [for]="'video-check-' + i"></label> <input [id]="'video-check-' + video.id" type="checkbox" [(ngModel)]="checkedVideos[video.id]" />
</div> <label [for]="'video-check-' + video.id"></label>
<my-video-thumbnail [video]="video"></my-video-thumbnail>
<div class="video-info">
<a class="video-info-name" [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name">{{ video.name }}</a>
<span class="video-info-date-views">{{ video.createdAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span>
</div>
<!-- Display only once -->
<div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0">
<div class="action-selection-mode-child">
<span class="action-button action-button-cancel-selection" (click)="abortSelectionMode()">
Cancel
</span>
<span class="action-button action-button-delete-selection" (click)="deleteSelectedVideos()">
<span class="icon icon-delete-white"></span>
Delete
</span>
</div> </div>
</div>
<div class="video-buttons" *ngIf="isInSelectionMode() === false"> <my-video-thumbnail [video]="video"></my-video-thumbnail>
<my-delete-button (click)="deleteVideo(video)"></my-delete-button>
<my-edit-button [routerLink]="[ '/videos', 'edit', video.uuid ]"></my-edit-button> <div class="video-info">
<a class="video-info-name" [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name">{{ video.name }}</a>
<span class="video-info-date-views">{{ video.createdAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span>
</div>
<!-- Display only once -->
<div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0 && j === 0">
<div class="action-selection-mode-child">
<span class="action-button action-button-cancel-selection" (click)="abortSelectionMode()">
Cancel
</span>
<span class="action-button action-button-delete-selection" (click)="deleteSelectedVideos()">
<span class="icon icon-delete-white"></span>
Delete
</span>
</div>
</div>
<div class="video-buttons" *ngIf="isInSelectionMode() === false">
<my-delete-button (click)="deleteVideo(video)"></my-delete-button>
<my-edit-button [routerLink]="[ '/videos', 'edit', video.uuid ]"></my-edit-button>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -45,16 +45,13 @@
display: flex; display: flex;
min-height: 130px; min-height: 130px;
padding-bottom: 20px; padding-bottom: 20px;
margin-bottom: 20px;
border-bottom: 1px solid #C6C6C6;
&:first-child { &:first-child {
margin-top: 47px; margin-top: 47px;
} }
&:not(:last-child) {
margin-bottom: 20px;
border-bottom: 1px solid #C6C6C6;
}
.checkbox-container { .checkbox-container {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -1,5 +1,7 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { immutableAssign } from '@app/shared/misc/utils'
import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
import { NotificationsService } from 'angular2-notifications' import { NotificationsService } from 'angular2-notifications'
import 'rxjs/add/observable/from' import 'rxjs/add/observable/from'
import 'rxjs/add/operator/concatAll' import 'rxjs/add/operator/concatAll'
@ -19,7 +21,9 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
titlePage = 'My videos' titlePage = 'My videos'
currentRoute = '/account/videos' currentRoute = '/account/videos'
checkedVideos: { [ id: number ]: boolean } = {} checkedVideos: { [ id: number ]: boolean } = {}
pagination = { videoHeight = 155
videoWidth = -1
pagination: ComponentPagination = {
currentPage: 1, currentPage: 1,
itemsPerPage: 10, itemsPerPage: 10,
totalItems: null totalItems: null
@ -46,8 +50,10 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
return Object.keys(this.checkedVideos).some(k => this.checkedVideos[k] === true) return Object.keys(this.checkedVideos).some(k => this.checkedVideos[k] === true)
} }
getVideosObservable () { getVideosObservable (page: number) {
return this.videoService.getMyVideos(this.pagination, this.sort) const newPagination = immutableAssign(this.pagination, { currentPage: page })
return this.videoService.getMyVideos(newPagination, this.sort)
} }
deleteSelectedVideos () { deleteSelectedVideos () {
@ -71,9 +77,12 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
Observable.from(observables) Observable.from(observables)
.concatAll() .concatAll()
.subscribe( .subscribe(
res => this.notificationsService.success('Success', `${toDeleteVideosIds.length} videos deleted.`), res => {
this.notificationsService.success('Success', `${toDeleteVideosIds.length} videos deleted.`)
this.buildVideoPages()
},
err => this.notificationsService.error('Error', err.message) err => this.notificationsService.error('Error', err.message)
) )
} }
) )
@ -89,6 +98,7 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
status => { status => {
this.notificationsService.success('Success', `Video ${video.name} deleted.`) this.notificationsService.success('Success', `Video ${video.name} deleted.`)
this.spliceVideosById(video.id) this.spliceVideosById(video.id)
this.buildVideoPages()
}, },
error => this.notificationsService.error('Error', error.message) error => this.notificationsService.error('Error', error.message)
@ -98,7 +108,14 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit
} }
private spliceVideosById (id: number) { private spliceVideosById (id: number) {
const index = this.videos.findIndex(v => v.id === id) for (const key of Object.keys(this.loadedPages)) {
this.videos.splice(index, 1) const videos = this.loadedPages[key]
const index = videos.findIndex(v => v.id === id)
if (index !== -1) {
videos.splice(index, 1)
return
}
}
} }
} }

View File

@ -55,6 +55,10 @@ function dateToHuman (date: string) {
return datePipe.transform(date, 'medium') return datePipe.transform(date, 'medium')
} }
function immutableAssign <A, B> (target: A, source: B) {
return Object.assign({}, target, source)
}
function isInSmallView () { function isInSmallView () {
return window.innerWidth < 600 return window.innerWidth < 600
} }
@ -70,5 +74,6 @@ export {
getAbsoluteAPIUrl, getAbsoluteAPIUrl,
dateToHuman, dateToHuman,
isInSmallView, isInSmallView,
isInMobileView isInMobileView,
immutableAssign
} }

View File

@ -4,13 +4,13 @@ import { NgModule } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { RouterModule } from '@angular/router' import { RouterModule } from '@angular/router'
import { MarkdownTextareaComponent } from '@app/shared/forms/markdown-textarea.component' import { MarkdownTextareaComponent } from '@app/shared/forms/markdown-textarea.component'
import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive'
import { MarkdownService } from '@app/videos/shared' import { MarkdownService } from '@app/videos/shared'
import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client' import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client'
import { BsDropdownModule } from 'ngx-bootstrap/dropdown' import { BsDropdownModule } from 'ngx-bootstrap/dropdown'
import { ModalModule } from 'ngx-bootstrap/modal' import { ModalModule } from 'ngx-bootstrap/modal'
import { TabsModule } from 'ngx-bootstrap/tabs' import { TabsModule } from 'ngx-bootstrap/tabs'
import { InfiniteScrollModule } from 'ngx-infinite-scroll'
import { BytesPipe, KeysPipe, NgPipesModule } from 'ngx-pipes' import { BytesPipe, KeysPipe, NgPipesModule } from 'ngx-pipes'
import { SharedModule as PrimeSharedModule } from 'primeng/components/common/shared' import { SharedModule as PrimeSharedModule } from 'primeng/components/common/shared'
@ -42,7 +42,6 @@ import { VideoService } from './video/video.service'
ModalModule.forRoot(), ModalModule.forRoot(),
PrimeSharedModule, PrimeSharedModule,
InfiniteScrollModule,
NgPipesModule, NgPipesModule,
TabsModule.forRoot() TabsModule.forRoot()
], ],
@ -55,7 +54,8 @@ import { VideoService } from './video/video.service'
EditButtonComponent, EditButtonComponent,
NumberFormatterPipe, NumberFormatterPipe,
FromNowPipe, FromNowPipe,
MarkdownTextareaComponent MarkdownTextareaComponent,
InfiniteScrollerDirective
], ],
exports: [ exports: [
@ -70,7 +70,6 @@ import { VideoService } from './video/video.service'
BsDropdownModule, BsDropdownModule,
ModalModule, ModalModule,
PrimeSharedModule, PrimeSharedModule,
InfiniteScrollModule,
BytesPipe, BytesPipe,
KeysPipe, KeysPipe,
@ -80,6 +79,7 @@ import { VideoService } from './video/video.service'
DeleteButtonComponent, DeleteButtonComponent,
EditButtonComponent, EditButtonComponent,
MarkdownTextareaComponent, MarkdownTextareaComponent,
InfiniteScrollerDirective,
NumberFormatterPipe, NumberFormatterPipe,
FromNowPipe FromNowPipe

View File

@ -6,17 +6,17 @@
<div *ngIf="pagination.totalItems === 0">No results.</div> <div *ngIf="pagination.totalItems === 0">No results.</div>
<div <div
class="videos" myInfiniteScroller
infiniteScroll [pageHeight]="pageHeight"
[infiniteScrollUpDistance]="1.5" (nearOfTop)="onNearOfTop()" (nearOfBottom)="onNearOfBottom()" (pageChanged)="onPageChanged($event)"
[infiniteScrollDistance]="0.5" class="videos" #videoElement
(scrolled)="onNearOfBottom()"
(scrolledUp)="onNearOfTop()"
> >
<my-video-miniature <div *ngFor="let videos of videoPages" class="videos-page">
class="ng-animate" <my-video-miniature
*ngFor="let video of videos" [video]="video" [user]="user" class="ng-animate"
> *ngFor="let video of videos" [video]="video" [user]="user"
</my-video-miniature> >
</my-video-miniature>
</div>
</div> </div>
</div> </div>

View File

@ -1,6 +1,7 @@
import { OnInit } from '@angular/core' import { ElementRef, OnInit, ViewChild, ViewChildren } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { isInMobileView, isInSmallView } from '@app/shared/misc/utils' import { isInMobileView } from '@app/shared/misc/utils'
import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive'
import { NotificationsService } from 'angular2-notifications' import { NotificationsService } from 'angular2-notifications'
import { Observable } from 'rxjs/Observable' import { Observable } from 'rxjs/Observable'
import { AuthService } from '../../core/auth' import { AuthService } from '../../core/auth'
@ -9,30 +10,35 @@ import { SortField } from './sort-field.type'
import { Video } from './video.model' import { Video } from './video.model'
export abstract class AbstractVideoList implements OnInit { export abstract class AbstractVideoList implements OnInit {
private static LINES_PER_PAGE = 3
@ViewChild('videoElement') videosElement: ElementRef
@ViewChild(InfiniteScrollerDirective) infiniteScroller: InfiniteScrollerDirective
pagination: ComponentPagination = { pagination: ComponentPagination = {
currentPage: 1, currentPage: 1,
itemsPerPage: 25, itemsPerPage: 10,
totalItems: null totalItems: null
} }
sort: SortField = '-createdAt' sort: SortField = '-createdAt'
defaultSort: SortField = '-createdAt' defaultSort: SortField = '-createdAt'
videos: Video[] = []
loadOnInit = true loadOnInit = true
pageHeight: number
videoWidth = 215
videoHeight = 230
videoPages: Video[][]
protected abstract notificationsService: NotificationsService protected abstract notificationsService: NotificationsService
protected abstract authService: AuthService protected abstract authService: AuthService
protected abstract router: Router protected abstract router: Router
protected abstract route: ActivatedRoute protected abstract route: ActivatedRoute
protected abstract currentRoute: string protected abstract currentRoute: string
abstract titlePage: string abstract titlePage: string
protected otherParams = {} protected loadedPages: { [ id: number ]: Video[] } = {}
protected otherRouteParams = {}
private loadedPages: { [ id: number ]: boolean } = {} abstract getVideosObservable (page: number): Observable<{ videos: Video[], totalVideos: number}>
abstract getVideosObservable (): Observable<{ videos: Video[], totalVideos: number}>
get user () { get user () {
return this.authService.getUser() return this.authService.getUser()
@ -45,15 +51,26 @@ export abstract class AbstractVideoList implements OnInit {
if (isInMobileView()) { if (isInMobileView()) {
this.pagination.itemsPerPage = 5 this.pagination.itemsPerPage = 5
this.videoWidth = -1
} }
if (this.loadOnInit === true) this.loadMoreVideos('after') if (this.videoWidth !== -1) {
const videosWidth = this.videosElement.nativeElement.offsetWidth
this.pagination.itemsPerPage = Math.floor(videosWidth / this.videoWidth) * AbstractVideoList.LINES_PER_PAGE
}
// Video takes all the width
if (this.videoWidth === -1) {
this.pageHeight = this.pagination.itemsPerPage * this.videoHeight
} else {
this.pageHeight = this.videoHeight * AbstractVideoList.LINES_PER_PAGE
}
if (this.loadOnInit === true) this.loadMoreVideos(this.pagination.currentPage)
} }
onNearOfTop () { onNearOfTop () {
if (this.pagination.currentPage > 1) { this.previousPage()
this.previousPage()
}
} }
onNearOfBottom () { onNearOfBottom () {
@ -62,16 +79,20 @@ export abstract class AbstractVideoList implements OnInit {
} }
} }
reloadVideos () { onPageChanged (page: number) {
this.videos = [] this.pagination.currentPage = page
this.loadedPages = {} this.setNewRouteParams()
this.loadMoreVideos('before')
} }
loadMoreVideos (where: 'before' | 'after') { reloadVideos () {
if (this.loadedPages[this.pagination.currentPage] === true) return this.loadedPages = {}
this.loadMoreVideos(this.pagination.currentPage)
}
const observable = this.getVideosObservable() loadMoreVideos (page: number) {
if (this.loadedPages[page] !== undefined) return
const observable = this.getVideosObservable(page)
observable.subscribe( observable.subscribe(
({ videos, totalVideos }) => { ({ videos, totalVideos }) => {
@ -82,13 +103,14 @@ export abstract class AbstractVideoList implements OnInit {
return this.reloadVideos() return this.reloadVideos()
} }
this.loadedPages[this.pagination.currentPage] = true this.loadedPages[page] = videos
this.buildVideoPages()
this.pagination.totalItems = totalVideos this.pagination.totalItems = totalVideos
if (where === 'before') { // Initialize infinite scroller now we loaded the first page
this.videos = videos.concat(this.videos) if (Object.keys(this.loadedPages).length === 1) {
} else { // Wait elements creation
this.videos = this.videos.concat(videos) setTimeout(() => this.infiniteScroller.initialize(), 500)
} }
}, },
error => this.notificationsService.error('Error', error.message) error => this.notificationsService.error('Error', error.message)
@ -107,17 +129,15 @@ export abstract class AbstractVideoList implements OnInit {
} }
protected previousPage () { protected previousPage () {
this.pagination.currentPage-- const min = this.minPageLoaded()
this.setNewRouteParams() if (min > 1) {
this.loadMoreVideos('before') this.loadMoreVideos(min - 1)
}
} }
protected nextPage () { protected nextPage () {
this.pagination.currentPage++ this.loadMoreVideos(this.maxPageLoaded() + 1)
this.setNewRouteParams()
this.loadMoreVideos('after')
} }
protected buildRouteParams () { protected buildRouteParams () {
@ -127,7 +147,7 @@ export abstract class AbstractVideoList implements OnInit {
page: this.pagination.currentPage page: this.pagination.currentPage
} }
return Object.assign(params, this.otherParams) return Object.assign(params, this.otherRouteParams)
} }
protected loadRouteParams (routeParams: { [ key: string ]: any }) { protected loadRouteParams (routeParams: { [ key: string ]: any }) {
@ -144,4 +164,16 @@ export abstract class AbstractVideoList implements OnInit {
const routeParams = this.buildRouteParams() const routeParams = this.buildRouteParams()
this.router.navigate([ this.currentRoute, routeParams ]) this.router.navigate([ this.currentRoute, routeParams ])
} }
protected buildVideoPages () {
this.videoPages = Object.values(this.loadedPages)
}
private minPageLoaded () {
return Math.min(...Object.keys(this.loadedPages).map(e => parseInt(e, 10)))
}
private maxPageLoaded () {
return Math.max(...Object.keys(this.loadedPages).map(e => parseInt(e, 10)))
}
} }

View File

@ -0,0 +1,77 @@
import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core'
import 'rxjs/add/operator/distinct'
import 'rxjs/add/operator/startWith'
import { fromEvent } from 'rxjs/observable/fromEvent'
@Directive({
selector: '[myInfiniteScroller]'
})
export class InfiniteScrollerDirective implements OnInit {
private static PAGE_VIEW_TOP_MARGIN = 500
@Input() containerHeight: number
@Input() pageHeight: number
@Input() percentLimit = 70
@Input() autoLoading = false
@Output() nearOfBottom = new EventEmitter<void>()
@Output() nearOfTop = new EventEmitter<void>()
@Output() pageChanged = new EventEmitter<number>()
private decimalLimit = 0
private lastCurrentBottom = -1
private lastCurrentTop = 0
constructor () {
this.decimalLimit = this.percentLimit / 100
}
ngOnInit () {
if (this.autoLoading === true) return this.initialize()
}
initialize () {
const scrollObservable = fromEvent(window, 'scroll')
.startWith(true)
.map(() => ({ current: window.scrollY, maximumScroll: document.body.clientHeight - window.innerHeight }))
// Scroll Down
scrollObservable
// Check we scroll down
.filter(({ current }) => {
const res = this.lastCurrentBottom < current
this.lastCurrentBottom = current
return res
})
.filter(({ current, maximumScroll }) => maximumScroll <= 0 || (current / maximumScroll) > this.decimalLimit)
.debounceTime(200)
.distinct()
.subscribe(() => this.nearOfBottom.emit())
// Scroll up
scrollObservable
// Check we scroll up
.filter(({ current }) => {
const res = this.lastCurrentTop > current
this.lastCurrentTop = current
return res
})
.filter(({ current, maximumScroll }) => {
return current !== 0 && (1 - (current / maximumScroll)) > this.decimalLimit
})
.debounceTime(200)
.distinct()
.subscribe(() => this.nearOfTop.emit())
// Page change
scrollObservable
.debounceTime(500)
.distinct()
.map(({ current }) => Math.max(1, Math.round((current + InfiniteScrollerDirective.PAGE_VIEW_TOP_MARGIN) / this.pageHeight)))
.distinctUntilChanged()
.subscribe(res => this.pageChanged.emit(res))
}
}

View File

@ -15,10 +15,9 @@
<div <div
class="comment-threads" class="comment-threads"
infiniteScroll myInfiniteScroller
[infiniteScrollUpDistance]="1.5" [autoLoading]="true"
[infiniteScrollDistance]="0.5" (nearOfBottom)="onNearOfBottom()"
(scrolled)="onNearOfBottom()"
> >
<div *ngFor="let comment of comments"> <div *ngFor="let comment of comments">
<my-video-comment <my-video-comment

View File

@ -160,11 +160,8 @@ export class VideoCommentsComponent implements OnChanges {
this.threadComments = {} this.threadComments = {}
this.threadLoading = {} this.threadLoading = {}
this.inReplyToCommentId = undefined this.inReplyToCommentId = undefined
this.componentPagination = { this.componentPagination.currentPage = 1
currentPage: 1, this.componentPagination.totalItems = null
itemsPerPage: 10,
totalItems: null
}
this.loadMoreComments() this.loadMoreComments()
} }

View File

@ -1,5 +1,6 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { immutableAssign } from '@app/shared/misc/utils'
import { NotificationsService } from 'angular2-notifications' import { NotificationsService } from 'angular2-notifications'
import { AuthService } from '../../core/auth' import { AuthService } from '../../core/auth'
import { AbstractVideoList } from '../../shared/video/abstract-video-list' import { AbstractVideoList } from '../../shared/video/abstract-video-list'
@ -28,7 +29,9 @@ export class VideoRecentlyAddedComponent extends AbstractVideoList implements On
super.ngOnInit() super.ngOnInit()
} }
getVideosObservable () { getVideosObservable (page: number) {
return this.videoService.getVideos(this.pagination, this.sort) const newPagination = immutableAssign(this.pagination, { currentPage: page })
return this.videoService.getVideos(newPagination, this.sort)
} }
} }

View File

@ -1,5 +1,6 @@
import { Component, OnDestroy, OnInit } from '@angular/core' import { Component, OnDestroy, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { immutableAssign } from '@app/shared/misc/utils'
import { NotificationsService } from 'angular2-notifications' import { NotificationsService } from 'angular2-notifications'
import { Subscription } from 'rxjs/Subscription' import { Subscription } from 'rxjs/Subscription'
import { AuthService } from '../../core/auth' import { AuthService } from '../../core/auth'
@ -16,7 +17,7 @@ export class VideoSearchComponent extends AbstractVideoList implements OnInit, O
currentRoute = '/videos/search' currentRoute = '/videos/search'
loadOnInit = false loadOnInit = false
protected otherParams = { protected otherRouteParams = {
search: '' search: ''
} }
private subActivatedRoute: Subscription private subActivatedRoute: Subscription
@ -35,9 +36,9 @@ export class VideoSearchComponent extends AbstractVideoList implements OnInit, O
this.subActivatedRoute = this.route.queryParams.subscribe( this.subActivatedRoute = this.route.queryParams.subscribe(
queryParams => { queryParams => {
const querySearch = queryParams['search'] const querySearch = queryParams['search']
if (!querySearch || this.otherParams.search === querySearch) return if (!querySearch || this.otherRouteParams.search === querySearch) return
this.otherParams.search = querySearch this.otherRouteParams.search = querySearch
this.reloadVideos() this.reloadVideos()
}, },
@ -51,7 +52,8 @@ export class VideoSearchComponent extends AbstractVideoList implements OnInit, O
} }
} }
getVideosObservable () { getVideosObservable (page: number) {
return this.videoService.searchVideos(this.otherParams.search, this.pagination, this.sort) const newPagination = immutableAssign(this.pagination, { currentPage: page })
return this.videoService.searchVideos(this.otherRouteParams.search, newPagination, this.sort)
} }
} }

View File

@ -1,5 +1,6 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { immutableAssign } from '@app/shared/misc/utils'
import { NotificationsService } from 'angular2-notifications' import { NotificationsService } from 'angular2-notifications'
import { AuthService } from '../../core/auth' import { AuthService } from '../../core/auth'
import { AbstractVideoList } from '../../shared/video/abstract-video-list' import { AbstractVideoList } from '../../shared/video/abstract-video-list'
@ -28,7 +29,8 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit
super.ngOnInit() super.ngOnInit()
} }
getVideosObservable () { getVideosObservable (page: number) {
return this.videoService.getVideos(this.pagination, this.sort) const newPagination = immutableAssign(this.pagination, { currentPage: page })
return this.videoService.getVideos(newPagination, this.sort)
} }
} }

View File

@ -4526,10 +4526,6 @@ ngx-clipboard@9.0.1:
dependencies: dependencies:
ngx-window-token "0.0.4" ngx-window-token "0.0.4"
ngx-infinite-scroll@0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/ngx-infinite-scroll/-/ngx-infinite-scroll-0.7.2.tgz#c1f0e7fba4731a55f15557dc6fce2721fd562420"
ngx-pipes@^2.0.5: ngx-pipes@^2.0.5:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/ngx-pipes/-/ngx-pipes-2.1.0.tgz#969cbc78f1c7512b12cc050f441c2528fb3a05a0" resolved "https://registry.yarnpkg.com/ngx-pipes/-/ngx-pipes-2.1.0.tgz#969cbc78f1c7512b12cc050f441c2528fb3a05a0"