102 lines
3.3 KiB
TypeScript
102 lines
3.3 KiB
TypeScript
import { ComponentRef, Injectable } from '@angular/core';
|
|
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';
|
|
import { Subject } from 'rxjs';
|
|
import { Debounce } from './decorators/debounce.decorator';
|
|
|
|
export interface OnAttach {
|
|
ngOnAttach(previousRoute?: ActivatedRouteSnapshot): void;
|
|
}
|
|
|
|
export interface OnDetach {
|
|
ngOnDetach(): void;
|
|
}
|
|
|
|
export function getReusableRouteKey(route: ActivatedRouteSnapshot): string {
|
|
return route.pathFromRoot
|
|
.map((el: ActivatedRouteSnapshot) => (el.routeConfig ? `${el.routeConfig.path}${JSON.stringify(el.params)}` : ''))
|
|
.filter(str => str.length > 0)
|
|
.join('');
|
|
}
|
|
|
|
interface RouteStorageObject {
|
|
readonly handle: DetachedRouteHandle;
|
|
readonly previousRoute: ActivatedRouteSnapshot;
|
|
}
|
|
|
|
@Injectable({ providedIn: 'root' })
|
|
export class CustomRouteReuseStrategy implements RouteReuseStrategy {
|
|
readonly #storedRoutes = new Map<string, RouteStorageObject>();
|
|
readonly attached$ = new Subject<ActivatedRouteSnapshot>();
|
|
readonly detached$ = new Subject<ActivatedRouteSnapshot>();
|
|
|
|
private static _removeTooltips(): void {
|
|
while (document.getElementsByTagName('mat-tooltip-component').length > 0) {
|
|
document.getElementsByTagName('mat-tooltip-component')[0].remove();
|
|
}
|
|
}
|
|
|
|
shouldDetach(route: ActivatedRouteSnapshot): boolean {
|
|
if (!route?.routeConfig?.data) {
|
|
return false;
|
|
}
|
|
return !!route.routeConfig.data['reuse'] && !!getReusableRouteKey(route);
|
|
}
|
|
|
|
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
|
|
if (handle === null) {
|
|
return;
|
|
}
|
|
CustomRouteReuseStrategy._removeTooltips();
|
|
|
|
const element = <{ componentRef: ComponentRef<OnDetach> } | undefined>handle;
|
|
|
|
if (element?.componentRef?.instance?.ngOnDetach) {
|
|
this._onDetach(element.componentRef.instance);
|
|
}
|
|
|
|
if (element) {
|
|
this.detached$.next(route);
|
|
}
|
|
|
|
this.#storedRoutes.set(getReusableRouteKey(route), {
|
|
handle: element as DetachedRouteHandle,
|
|
previousRoute: route,
|
|
});
|
|
}
|
|
|
|
shouldAttach(route: ActivatedRouteSnapshot): boolean {
|
|
return this.#storedRoutes.has(getReusableRouteKey(route));
|
|
}
|
|
|
|
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
|
|
const key = getReusableRouteKey(route);
|
|
const value = this.#storedRoutes.get(key);
|
|
const element = <{ componentRef: ComponentRef<OnAttach> } | undefined>value?.handle;
|
|
|
|
if (element?.componentRef?.instance.ngOnAttach && value) {
|
|
this._onAttach(element.componentRef.instance, value.previousRoute);
|
|
setTimeout(() => this.#storedRoutes.delete(key));
|
|
}
|
|
|
|
if (element) {
|
|
this.attached$.next(route);
|
|
}
|
|
|
|
return element as DetachedRouteHandle;
|
|
}
|
|
|
|
shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
|
|
return getReusableRouteKey(future) === getReusableRouteKey(current);
|
|
}
|
|
|
|
@Debounce()
|
|
private _onAttach(instance: OnAttach, previousRoute?: ActivatedRouteSnapshot) {
|
|
instance.ngOnAttach(previousRoute);
|
|
}
|
|
|
|
@Debounce()
|
|
private _onDetach(instance: OnDetach) {
|
|
instance.ngOnDetach();
|
|
}
|
|
}
|