UNPKG

@datorama/akita

Version:

A Reactive State Management Tailored-Made for JS Applications

283 lines 8.04 kB
import { __decorate, __metadata } from "tslib"; import { BehaviorSubject, delay, from, isObservable, map, switchMap, take } from 'rxjs'; import { action, logAction } from '../../actions'; import { isNil } from '../../isNil'; import { isUndefined } from '../../isUndefined'; import { applyTransaction } from '../../transaction'; import { AkitaPlugin } from '../plugin'; const paginatorDefaults = { pagesControls: false, range: false, startWith: 1, cacheTimeout: undefined, clearStoreWithCache: true, }; export class PaginatorPlugin extends AkitaPlugin { constructor(query, config = {}) { super(query, { resetFn: () => { this.initial = false; this.destroy({ clearCache: true, currentPage: 1 }); }, }); this.query = query; this.config = config; /** Save current filters, sorting, etc. in cache */ this.metadata = new Map(); this.pages = new Map(); this.pagination = { currentPage: 1, perPage: 0, total: 0, lastPage: 0, data: [], }; /** * When the user navigates to a different page and return * we don't want to call `clearCache` on first time. */ this.initial = true; /** * Proxy to the query loading */ this.isLoading$ = this.query.selectLoading().pipe(delay(0)); this.config = { ...paginatorDefaults, ...config }; const { startWith, cacheTimeout } = this.config; this.page = new BehaviorSubject(startWith); if (isObservable(cacheTimeout)) { this.clearCacheSubscription = cacheTimeout.subscribe(() => this.clearCache()); } } /** * Listen to page changes */ get pageChanges() { return this.page.asObservable(); } /** * Get the current page number */ get currentPage() { return this.pagination.currentPage; } /** * Check if current page is the first one */ get isFirst() { return this.currentPage === 1; } /** * Check if current page is the last one */ get isLast() { return this.currentPage === this.pagination.lastPage; } /** * Whether to generate an array of pages for *ngFor * [1, 2, 3, 4] */ withControls() { this.config.pagesControls = true; return this; } /** * Whether to generate the `from` and `to` keys * [1, 2, 3, 4] */ withRange() { this.config.range = true; return this; } /** * Set the loading state */ setLoading(value = true) { this.getStore().setLoading(value); } /** * Update the pagination object and add the page */ update(response) { this.pagination = response; this.addPage(response.data); } /** * * Set the ids and add the page to store */ addPage(data) { this.pages.set(this.currentPage, { ids: data.map((entity) => entity[this.getStore().idKey]) }); this.getStore().upsertMany(data); } /** * Clear the cache. */ clearCache(options = {}) { if (!this.initial) { logAction('@Pagination - Clear Cache'); if (options.clearStore !== false && (this.config.clearStoreWithCache || options.clearStore)) { this.getStore().remove(); } this.pages = new Map(); this.metadata = new Map(); } this.initial = false; } clearPage(page) { this.pages.delete(page); } /** * Clear the cache timeout and optionally the pages */ destroy({ clearCache, currentPage } = {}) { if (this.clearCacheSubscription) { this.clearCacheSubscription.unsubscribe(); } if (clearCache) { this.clearCache(); } if (!isUndefined(currentPage)) { this.setPage(currentPage); } this.initial = true; } /** * Whether the provided page is active */ isPageActive(page) { return this.currentPage === page; } /** * Set the current page */ setPage(page) { if (page !== this.currentPage || !this.hasPage(page)) { this.page.next((this.pagination.currentPage = page)); } } /** * Increment current page */ nextPage() { if (this.currentPage !== this.pagination.lastPage) { this.setPage(this.pagination.currentPage + 1); } } /** * Decrement current page */ prevPage() { if (this.pagination.currentPage > 1) { this.setPage(this.pagination.currentPage - 1); } } /** * Set current page to last */ setLastPage() { this.setPage(this.pagination.lastPage); } /** * Set current page to first */ setFirstPage() { this.setPage(1); } /** * Check if page exists in cache */ hasPage(page) { return this.pages.has(page); } /** * Get the current page if it's in cache, otherwise invoke the request */ getPage(req) { let page = this.pagination.currentPage; if (this.hasPage(page)) { return this.selectPage(page); } else { this.setLoading(true); return from(req()).pipe(switchMap((config) => { page = config.currentPage; applyTransaction(() => { this.setLoading(false); this.update(config); }); return this.selectPage(page); })); } } getQuery() { return this.query; } refreshCurrentPage() { if (isNil(this.currentPage) === false) { this.clearPage(this.currentPage); this.setPage(this.currentPage); } } getFrom() { if (this.isFirst) { return 1; } return (this.currentPage - 1) * this.pagination.perPage + 1; } getTo() { if (this.isLast) { return this.pagination.total; } return this.currentPage * this.pagination.perPage; } /** * Select the page */ selectPage(page) { return this.query.selectAll({ asObject: true }).pipe(take(1), map((entities) => { const response = { ...this.pagination, data: this.pages.get(page).ids.map((id) => entities[id]), }; const { range, pagesControls } = this.config; /** If no total - calc it */ if (isNaN(this.pagination.total)) { if (response.lastPage === 1) { response.total = response.data ? response.data.length : 0; } else { response.total = response.perPage * response.lastPage; } this.pagination.total = response.total; } if (range) { response.from = this.getFrom(); response.to = this.getTo(); } if (pagesControls) { response.pageControls = generatePages(this.pagination.total, this.pagination.perPage); } return response; })); } } __decorate([ action('@Pagination - New Page'), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", void 0) ], PaginatorPlugin.prototype, "update", null); /** * Generate an array so we can ngFor them to navigate between pages */ function generatePages(total, perPage) { const len = Math.ceil(total / perPage); const arr = []; for (let i = 0; i < len; i++) { arr.push(i + 1); } return arr; } /** backward compatibility */ export const Paginator = PaginatorPlugin; //# sourceMappingURL=paginatorPlugin.js.map