import { Injectable } from '@angular/core' ; import { Effect , Actions , ofType } from '@ngrx/effects' ; import { Store , Action } from '@ngrx/store' ; import { Observable , of } from 'rxjs' ; import { map , switchMap , takeUntil , withLatestFrom , catchError } from 'rxjs/operators' ; import { SearchService , SearchServiceConfig } from '../services' ; import * as apiAction from '../actions/api' ; import * as paginationAction from '../actions/pagination' ; import * as fromRoot from '../reducers' ; /**
 * Effects offer a way to isolate and easily test side-effects within your
 * application. StateUpdates is an observable of the latest state and
 * dispatched action. The `toPayload` helper function returns just
 * the payload of the currently dispatched action, useful in
 * instances where the current state is not necessary.
 *
 * A simple way to think of it is that ngrx/effects is an event listener of sorts.
 * It listens for actions being dispatched to the store. You can then tell `ngrx/effects`
 * that when a particular action is dispatched, to take another, new action as a result.
 * At the end, what’s really happening is `ngrx/effects` is an `action generator` that dispatches
 * a `new action` as a result of a different action.
 */ @ Injectable ( ) export class PaginationEffects { private searchServiceConfig : SearchServiceConfig = new SearchServiceConfig ( ) ; @ Effect ( ) pagination$ : Observable < Action > = this . actions$ . pipe ( ofType ( paginationAction . ActionTypes . NEXT_PAGE ) , map ( ( action ) => action . payload ) , withLatestFrom ( this . store$ ) , map ( ( [ action , state ] ) => { return { query : state . query , lastRecord : state . apiResponse . entities . length , } ; } ) , switchMap ( queryObject => { const nextSearch$ = this . actions$ . ofType ( apiAction . ActionTypes . SEARCH ) ; this . searchServiceConfig . startRecord = queryObject . lastRecord + 1 ; this . searchServiceConfig . addAggregationFields ( [ 'created_at' , 'screen_name' , 'mentions' , 'hashtags' ] ) ; if ( queryObject . query . filter . image ) { this . searchServiceConfig . addFilters ( [ 'image' ] ) ; } else { this . searchServiceConfig . removeFilters ( [ 'image' ] ) ; } if ( queryObject . query . filter . video ) { this . searchServiceConfig . addFilters ( [ 'video' ] ) ; } else { this . searchServiceConfig . removeFilters ( [ 'video' ] ) ; } return this . apiSearchService . fetchQuery ( queryObject . query . queryString , this . searchServiceConfig ) . pipe ( takeUntil ( nextSearch$ ) , map ( response => { return new paginationAction . PaginationCompleteSuccessAction ( response ) ; } ) , catchError ( ( ) => of ( new paginationAction . PaginationCompleteFailAction ( '' ) ) ) ) ; } ) ) ; constructor ( private actions$ , private apiSearchService , private store$ ) { } }