UNPKG

@ngxs/router-plugin

Version:

router plugin for @ngxs/store

387 lines (379 loc) 14.7 kB
import * as i0 from '@angular/core'; import { inject, NgZone, Injectable, NgModule, makeEnvironmentProviders } from '@angular/core'; import * as i1 from '@ngxs/store'; import { StateToken, Store, Action, Selector, State, NgxsModule, provideStates } from '@ngxs/store'; import { ɵNGXS_ROUTER_PLUGIN_OPTIONS as _NGXS_ROUTER_PLUGIN_OPTIONS, ɵUSER_OPTIONS as _USER_OPTIONS, ɵcreateRouterPluginOptions as _createRouterPluginOptions } from '@ngxs/router-plugin/internals'; import { __decorate, __metadata } from 'tslib'; import { Router, NavigationStart, RoutesRecognized, ResolveEnd, NavigationCancel, NavigationError, NavigationEnd } from '@angular/router'; import { ReplaySubject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; /** * Public event api of the router */ class Navigate { static { this.type = '[Router] Navigate'; } constructor(path, queryParams, extras) { this.path = path; this.queryParams = queryParams; this.extras = extras; } } /** * * Angular Routers internal state events * */ /** * An action dispatched when the router starts the navigation. */ class RouterRequest { static { this.type = '[Router] RouterRequest'; } constructor(routerState, event, trigger = 'none') { this.routerState = routerState; this.event = event; this.trigger = trigger; } } /** * An action dispatched when the router navigates. */ class RouterNavigation { static { this.type = '[Router] RouterNavigation'; } constructor(routerState, event, trigger = 'none') { this.routerState = routerState; this.event = event; this.trigger = trigger; } } /** * An action dispatched when the router cancel navigation. */ class RouterCancel { static { this.type = '[Router] RouterCancel'; } constructor(routerState, storeState, event, trigger = 'none') { this.routerState = routerState; this.storeState = storeState; this.event = event; this.trigger = trigger; } } /** * An action dispatched when the router errors. */ class RouterError { static { this.type = '[Router] RouterError'; } constructor(routerState, storeState, event, trigger = 'none') { this.routerState = routerState; this.storeState = storeState; this.event = event; this.trigger = trigger; } } /** * An action dispatched when the `ResolveEnd` event is triggered. */ class RouterDataResolved { static { this.type = '[Router] RouterDataResolved'; } constructor(routerState, event, trigger = 'none') { this.routerState = routerState; this.event = event; this.trigger = trigger; } } /** * An action dispatched when the router navigation has been finished successfully. */ class RouterNavigated { static { this.type = '[Router] RouterNavigated'; } constructor(routerState, event, trigger = 'none') { this.routerState = routerState; this.event = event; this.trigger = trigger; } } class RouterStateSerializer { } class DefaultRouterStateSerializer { serialize(routerState) { return { root: this.serializeRoute(routerState.root), url: routerState.url }; } serializeRoute(route) { const children = route.children.map(c => this.serializeRoute(c)); return { url: route.url, title: route.title, params: route.params, queryParams: route.queryParams, fragment: route.fragment, data: route.data, outlet: route.outlet, component: null, routeConfig: null, root: null, parent: null, firstChild: children[0], children: children, pathFromRoot: null, paramMap: route.paramMap, queryParamMap: route.queryParamMap, toString: route.toString }; } } // NGXS doesn't permit untyped selectors, such as `select(RouterState)`, // as the `RouterState` class itself lacks type information. Therefore, // the following state token must replace `RouterState`. const ROUTER_STATE_TOKEN = new StateToken('router'); let RouterState = class RouterState { static state(state) { // The `state` is optional if the selector is invoked before the router // state is registered in NGXS. return state?.state; } static url(state) { return state?.state?.url; } constructor() { this._store = inject(Store); this._router = inject(Router); this._serializer = inject(RouterStateSerializer); this._ngZone = inject(NgZone); /** * Determines how navigation was performed by the `RouterState` itself * or outside via `new Navigate(...)` */ this._trigger = 'none'; /** * That's the serialized state from the `Router` class */ this._routerState = null; /** * That's the value of the `RouterState` state */ this._storeState = null; this._lastEvent = null; this._options = inject(_NGXS_ROUTER_PLUGIN_OPTIONS); this._destroy$ = new ReplaySubject(1); this._setUpStoreListener(); this._setUpRouterEventsListener(); } ngOnDestroy() { this._destroy$.next(); } navigate(_, action) { return this._ngZone.run(() => this._router.navigate(action.path, { queryParams: action.queryParams, ...action.extras })); } angularRouterAction(ctx, action) { ctx.setState({ trigger: action.trigger, state: action.routerState, navigationId: action.event.id }); } _setUpStoreListener() { const routerState$ = this._store .select(ROUTER_STATE_TOKEN) .pipe(takeUntil(this._destroy$)); routerState$.subscribe((state) => { this._navigateIfNeeded(state); }); } _navigateIfNeeded(routerState) { if (routerState && routerState.trigger === 'devtools') { this._storeState = this._store.selectSnapshot(ROUTER_STATE_TOKEN); } const canSkipNavigation = !this._storeState || !this._storeState.state || !routerState || routerState.trigger === 'router' || this._router.url === this._storeState.state.url || this._lastEvent instanceof NavigationStart; if (canSkipNavigation) { return; } this._storeState = this._store.selectSnapshot(ROUTER_STATE_TOKEN); this._trigger = 'store'; this._ngZone.run(() => this._router.navigateByUrl(this._storeState.state.url)); } _setUpRouterEventsListener() { const dispatchRouterNavigationLate = this._options != null && this._options.navigationActionTiming === 2 /* NavigationActionTiming.PostActivation */; let lastRoutesRecognized; const events$ = this._router.events.pipe(takeUntil(this._destroy$)); events$.subscribe(event => { this._lastEvent = event; if (event instanceof NavigationStart) { this._navigationStart(event); } else if (event instanceof RoutesRecognized) { lastRoutesRecognized = event; if (!dispatchRouterNavigationLate && this._trigger !== 'store') { this._dispatchRouterNavigation(lastRoutesRecognized); } } else if (event instanceof ResolveEnd) { this._dispatchRouterDataResolved(event); } else if (event instanceof NavigationCancel) { this._dispatchRouterCancel(event); this._reset(); } else if (event instanceof NavigationError) { this._dispatchRouterError(event); this._reset(); } else if (event instanceof NavigationEnd) { if (this._trigger !== 'store') { if (dispatchRouterNavigationLate) { this._dispatchRouterNavigation(lastRoutesRecognized); } this._dispatchRouterNavigated(event); } this._reset(); } }); } /** Reacts to `NavigationStart`. */ _navigationStart(event) { this._routerState = this._serializer.serialize(this._router.routerState.snapshot); if (this._trigger !== 'none') { this._storeState = this._store.selectSnapshot(ROUTER_STATE_TOKEN); this._dispatchRouterAction(new RouterRequest(this._routerState, event, this._trigger)); } } /** Reacts to `ResolveEnd`. */ _dispatchRouterDataResolved(event) { const routerState = this._serializer.serialize(event.state); this._dispatchRouterAction(new RouterDataResolved(routerState, event, this._trigger)); } /** Reacts to `RoutesRecognized` or `NavigationEnd`, depends on the `navigationActionTiming`. */ _dispatchRouterNavigation(lastRoutesRecognized) { const nextRouterState = this._serializer.serialize(lastRoutesRecognized.state); this._dispatchRouterAction(new RouterNavigation(nextRouterState, new RoutesRecognized(lastRoutesRecognized.id, lastRoutesRecognized.url, lastRoutesRecognized.urlAfterRedirects, nextRouterState), this._trigger)); } /** Reacts to `NavigationCancel`. */ _dispatchRouterCancel(event) { this._dispatchRouterAction(new RouterCancel(this._routerState, this._storeState, event, this._trigger)); } /** Reacts to `NavigationEnd`. */ _dispatchRouterError(event) { this._dispatchRouterAction(new RouterError(this._routerState, this._storeState, new NavigationError(event.id, event.url, `${event}`), this._trigger)); } /** Reacts to `NavigationEnd`. */ _dispatchRouterNavigated(event) { const routerState = this._serializer.serialize(this._router.routerState.snapshot); this._dispatchRouterAction(new RouterNavigated(routerState, event, this._trigger)); } _dispatchRouterAction(action) { this._trigger = 'router'; try { this._store.dispatch(action); } finally { this._trigger = 'none'; } } _reset() { this._trigger = 'none'; this._storeState = null; this._routerState = null; } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: RouterState, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } /** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: RouterState }); } }; __decorate([ Action(Navigate), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Navigate]), __metadata("design:returntype", void 0) ], RouterState.prototype, "navigate", null); __decorate([ Action([ (RouterRequest), (RouterNavigation), (RouterError), (RouterCancel), (RouterDataResolved), (RouterNavigated) ]), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", void 0) ], RouterState.prototype, "angularRouterAction", null); __decorate([ Selector(), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", void 0) ], RouterState, "state", null); __decorate([ Selector(), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Object) ], RouterState, "url", null); RouterState = __decorate([ State({ name: ROUTER_STATE_TOKEN, defaults: { state: undefined, navigationId: undefined, trigger: 'none' } }), __metadata("design:paramtypes", []) ], RouterState); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: RouterState, decorators: [{ type: Injectable }], ctorParameters: () => [], propDecorators: { navigate: [], angularRouterAction: [] } }); class NgxsRouterPluginModule { static forRoot(options) { return { ngModule: NgxsRouterPluginModule, providers: [ { provide: _USER_OPTIONS, useValue: options }, { provide: _NGXS_ROUTER_PLUGIN_OPTIONS, useFactory: _createRouterPluginOptions, deps: [_USER_OPTIONS] }, { provide: RouterStateSerializer, useClass: DefaultRouterStateSerializer } ] }; } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: NgxsRouterPluginModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } /** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.0", ngImport: i0, type: NgxsRouterPluginModule, imports: [i1.ɵNgxsFeatureModule] }); } /** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: NgxsRouterPluginModule, imports: [NgxsModule.forFeature([RouterState])] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: NgxsRouterPluginModule, decorators: [{ type: NgModule, args: [{ imports: [NgxsModule.forFeature([RouterState])] }] }] }); function withNgxsRouterPlugin(options) { return makeEnvironmentProviders([ provideStates([RouterState]), { provide: _USER_OPTIONS, useValue: options }, { provide: _NGXS_ROUTER_PLUGIN_OPTIONS, useFactory: _createRouterPluginOptions, deps: [_USER_OPTIONS] }, { provide: RouterStateSerializer, useClass: DefaultRouterStateSerializer } ]); } /** * The public api for consumers of @ngxs/router-plugin */ /** * Generated bundle index. Do not edit. */ export { DefaultRouterStateSerializer, Navigate, NgxsRouterPluginModule, ROUTER_STATE_TOKEN, RouterCancel, RouterDataResolved, RouterError, RouterNavigated, RouterNavigation, RouterRequest, RouterState, RouterStateSerializer, withNgxsRouterPlugin }; //# sourceMappingURL=ngxs-router-plugin.mjs.map