@bespunky/angular-zen
Version:
The Angular tools you always wished were there.
128 lines (120 loc) • 6.03 kB
JavaScript
import { filter, Observable, switchMap, merge, map, shareReplay } from 'rxjs';
import { inject } from '@angular/core';
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
import { RouterOutletComponentBus } from '@bespunky/angular-zen/router-x';
/**
* Creates an observable which emits only the specified routing event.
*
* @export
* @template T The type of router event to observe.
* @param {Type<T>} eventType The type of router event to observe.
* @return {Observable<T>} An observable which emits only the specified routing event.
*/
function useRouterEvent(eventType) {
const router = inject(Router);
return router.events.pipe(filter((event) => event instanceof eventType));
}
/**
* Recoursively runs a processing function on the route and its children.
* Scan is done from parent to child, meaning the parent is the first to process.
*
* @export
* @param {(RouterOutletComponentBus | null)} componentBus The instance of the component bus.
* @param {ActivatedRouteSnapshot} route The top route on which to apply the processing function.
* @param {RouteProcessFunction} process The function to run on the route and its children.
* The function receives a `route` argument which reflects the route being processed,
* and a `component` argument which reflects the instance of the component loaded for the route's corresponsind outlet.
* If the corresponding outlet wasn't marked with the `publishComponent` directive, the `component` argument will be null.
* @param {number} [levels=-1] (Optional) The number of levels (excluding the parent) to dive deeper into the route tree.
* A value of 1 for example, will process the route and its first-level children only. By default, scans all levels of the route tree.
*/
function deepScanRoute(componentBus, route, process, levels = -1) {
// Make sure the caller wants scan to proceed, then make sure level limit wasn't reached.
const processing = process(route, componentBus === null || componentBus === void 0 ? void 0 : componentBus.instance(route.outlet));
// Negative values will scan all, positives will scan until reaching zero.
const shouldScanChildren = !processing.done && levels !== 0;
if (shouldScanChildren && route.children)
route.children.forEach(childRoute => deepScanRoute(componentBus, childRoute, process, levels - 1));
}
function observeRouteDeepScan(route, componentBus, process, levels) {
return new Observable(({ next, error, complete }) => {
const processAndEmit = (...args) => {
const result = process(...args);
if (result.emit)
next(result.emit);
return result;
};
try {
deepScanRoute(componentBus, route, processAndEmit, levels);
}
catch (e) {
error(e);
}
finally {
complete();
}
});
}
/**
* Creates an observable which, upon navigation end, deep scans the activated route by running the provided
* processing function.
*
* @export
* @template TResult The type of the value emitted by the provided processing function.
* @param {ObservedRouteProcessFunction<TResult>} process The function to run on the activated route and its children.
* @param {number} [levels=-1] (Optional) The number of levels (excluding the parent) to dive deeper into the route tree.
* A value of 1 for example, will process the route and its first-level children only. By default, scans all levels of the route tree.
* @return {Observable<TResult>} An observable which, upon navigation end, deep scans the activated route by running the provided
* processing function.
*/
function useRouteDeepScan(process, levels = -1) {
const route = inject(ActivatedRoute);
const componentBus = inject(RouterOutletComponentBus);
return useRouterEvent(NavigationEnd).pipe(switchMap(() => observeRouteDeepScan(route.snapshot, componentBus, process, levels)));
}
/**
* Creates an observable which emits only the specified router events.
*
* @export
* @param {readonly [...Events]} eventTypes
* @template Events The types of events to observe.
* @returns {Observable<TypeInstance<Events[number]>>} An observable which emits only the specified router events.
*/
function useRouterEvents(...eventTypes) {
return inject(Router).events.pipe(filter((event) => eventTypes.some(eventType => event instanceof eventType)));
}
/**
* Creates an observable which emits the latest state of the published router outlets in the app.
* The emitted state is a dictionary of outlet names and corresponding component instances.
*
* @see `PublishComponentDirective` for more details.
*
* @export
* @return {Observable<Map<string, AnyObject | null>>} An observable which emits the latest state of the published router outlets in the app.
*/
function useRouterOutletStateTracker() {
const componentBus = inject(RouterOutletComponentBus);
return merge([componentBus.componentPublished, componentBus.componentUnpublished]).pipe(map(() => componentBus.outletsState), shareReplay(1));
}
/**
* Creates an observable which emits the latest component instance for the currently activated route.
*
* @see `PublishComponentDirective` for more details.
*
* @export
* @return {Observable<ActivatedRouteWithComponent>} An observable which emits the component instance for the currently activated route.
*/
function useActivatedRouteComponent() {
const componentBus = inject(RouterOutletComponentBus);
const route = inject(ActivatedRoute);
return useRouterEvent(NavigationEnd).pipe(map(() => ({
component: componentBus.instance(route.outlet),
route: route.snapshot
})), shareReplay(1));
}
// export * from './lib/use-activated-route-component-resolves';
/**
* Generated bundle index. Do not edit.
*/
export { deepScanRoute, useActivatedRouteComponent, useRouteDeepScan, useRouterEvent, useRouterEvents, useRouterOutletStateTracker };
//# sourceMappingURL=bespunky-angular-zen-router-x-utils.mjs.map