Skip to content

Instantly share code, notes, and snippets.

@zdennis
Created February 21, 2019 22:07
Show Gist options
  • Save zdennis/8f931f44acd18ac3933e45ce901edcaf to your computer and use it in GitHub Desktop.
Save zdennis/8f931f44acd18ac3933e45ce901edcaf to your computer and use it in GitHub Desktop.
Angular: Service-layer caching based on routing / navigation events
import {
Component,
OnInit,
Input,
OnDestroy,
ViewChild,
} from '@angular/core';
import { Order } from '../../orders/order';
import { Subscription } from 'rxjs';
import { ActivatedRoute, Data } from '@angular/router';
import { IonRefresher } from '@ionic/angular';
import { RouteDataResolutionService, RouteDataResolver } from 'src/app/framework-ext/route-data-resolution.service';
@Component({
selector: 'app-order-list-page',
templateUrl: './order-list-page.component.html',
styleUrls: ['./order-list-page.component.scss']
})
export class OrderListPageComponent implements OnInit, OnDestroy {
@Input() orders: Order[] = [];
@ViewChild(IonRefresher)
refresher: IonRefresher;
private refreshing = false;
private routeDataResolver: RouteDataResolver;
private subscriptions: Subscription[] = [];
constructor(
private activatedRoute: ActivatedRoute,
private routeDataResolutionService: RouteDataResolutionService,
) {}
ngOnInit() {
this.routeDataResolver = this.routeDataResolutionService.resolverFor(this.activatedRoute);
this.subscriptions.push(
this.routeDataResolver.data.subscribe(data => this.routeDataResolved(data))
);
}
ngOnDestroy() {
this.subscriptions.forEach(s => s.unsubscribe());
}
ionViewWillEnter() {
this.routeDataResolver.resolve();
}
doRefresh() {
this.refreshing = true;
this.routeDataResolver.resolve();
}
routeDataResolved(data: Data) {
this.orders = data.orders;
if (this.refreshing) {
this.refreshing = false;
this.refresher.complete();
}
}
}
import { Injectable } from '@angular/core';
import { Observable, ReplaySubject } from 'rxjs';
import { Router, NavigationStart, NavigationEnd } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class RouterCacheService {
constructor(private router: Router) {}
createCacheStore(): RouterCacheStore {
return new RouterCacheStore(this.router);
}
}
export class RouterCacheStore {
private _cache: { [k: string]: any } = {};
private _shouldCache = false;
constructor(private router: Router) {
this.router.events.subscribe(event => {
if (event instanceof NavigationStart) {
this._shouldCache = true;
} else if (event instanceof NavigationEnd) {
this._shouldCache = false;
this._cache = {};
}
});
}
cacheObservable<T>(key, fn: () => Observable<T>): Observable<T> {
if (!this._shouldCache) {
return fn();
} else {
const subject = this._cache[key] || new ReplaySubject<T>(1);
if (!this._cache.hasOwnProperty(key)) {
fn().subscribe(
results => {
this._cache[key] = subject;
subject.next(results);
},
error => subject.error(error),
() => subject.complete()
);
}
return subject.asObservable();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment