1- import { computed , inject , Injectable , Signal , Type } from '@angular/core' ;
1+ import { InjectionToken , Signal , Type , computed , inject } from '@angular/core' ;
22import { takeUntilDestroyed } from '@angular/core/rxjs-interop' ;
33import {
4- Event as RouterEvent ,
54 NavigationCancel ,
65 NavigationEnd ,
76 NavigationError ,
87 NavigationStart ,
98 Router ,
9+ Event as RouterEvent ,
1010 RoutesRecognized ,
1111} from '@angular/router' ;
12- import { patchState , signalStore , withState } from '@ngrx/signals' ;
13- import { map , Observable } from 'rxjs' ;
12+ import {
13+ patchState ,
14+ signalStore ,
15+ withComputed ,
16+ withHooks ,
17+ withMethods ,
18+ withState ,
19+ } from '@ngrx/signals' ;
20+ import { Observable , map } from 'rxjs' ;
1421import { MinimalActivatedRouteSnapshot } from '../@ngrx/router-store/minimal-activated-route-state-snapshot' ;
1522import { MinimalRouterStateSnapshot } from '../@ngrx/router-store/minimal-router-state-snapshot' ;
1623import { MinimalRouterStateSerializer } from '../@ngrx/router-store/minimal_serializer' ;
@@ -20,102 +27,98 @@ import { InternalStrictRouteData } from '../internal-strict-route-data';
2027import { InternalStrictRouteParams } from '../internal-strict-route-params' ;
2128import { RouterSignalStore } from '../router-signal-store' ;
2229
23- interface GlobalRouterState {
24- readonly routerState : MinimalRouterStateSnapshot ;
30+ interface GlobalRouterSignalState {
31+ readonly _routerState : MinimalRouterStateSnapshot ;
2532}
2633
27- const GlobalRouterSignalStoreBase = signalStore (
28- withState < GlobalRouterState > ( {
29- routerState : { } as MinimalRouterStateSnapshot ,
30- } )
31- ) ;
32-
33- @Injectable ( )
34- export class GlobalRouterSignalStore
35- extends GlobalRouterSignalStoreBase
36- implements RouterSignalStore
37- {
38- #router = inject ( Router ) ;
39- #serializer = inject ( MinimalRouterStateSerializer ) ;
34+ function createInitialGlobalRouterSignalState ( ) : GlobalRouterSignalState {
35+ const router = inject ( Router ) ;
36+ const serializer = inject ( MinimalRouterStateSerializer ) ;
4037
41- #rootRoute: Signal < MinimalActivatedRouteSnapshot > = computed (
42- ( ) => this . routerState ( ) . root
43- ) ;
38+ return {
39+ _routerState : serializer . serialize ( router . routerState . snapshot ) ,
40+ } ;
41+ }
4442
45- currentRoute : Signal < MinimalActivatedRouteSnapshot > = computed ( ( ) => {
46- let route = this . #rootRoute( ) ;
47- while ( route . firstChild ) {
48- route = route . firstChild ;
43+ const initialGlobalRouterSignalStateToken =
44+ new InjectionToken < GlobalRouterSignalState > (
45+ 'initialGlobalRouterSignalStateToken' ,
46+ {
47+ factory : createInitialGlobalRouterSignalState ,
4948 }
50- return route ;
51- } ) ;
52-
53- fragment : Signal < string | null > = computed ( ( ) => this . #rootRoute( ) . fragment ) ;
54-
55- queryParams : Signal < InternalStrictQueryParams > = computed (
56- ( ) => this . #rootRoute( ) . queryParams
5749 ) ;
5850
59- routeData : Signal < InternalStrictRouteData > = computed (
60- ( ) => this . currentRoute ( ) . data
61- ) ;
62-
63- routeParams : Signal < InternalStrictRouteParams > = computed (
64- ( ) => this . currentRoute ( ) . params
65- ) ;
66-
67- title : Signal < string | undefined > = computed ( ( ) => this . currentRoute ( ) . title ) ;
68-
69- url : Signal < string > = computed ( ( ) => this . routerState ( ) . url ) ;
70-
71- constructor ( ) {
72- super ( ) ;
73-
74- // Initialize state with current router snapshot
75- patchState ( this , {
76- routerState : this . #serializer. serialize (
77- this . #router. routerState . snapshot
78- ) ,
79- } ) ;
80-
81- // Subscribe to router events and update state
82- this . selectRouterEvents (
83- NavigationStart ,
84- RoutesRecognized ,
85- NavigationEnd ,
86- NavigationCancel ,
87- NavigationError
88- )
89- . pipe (
90- map ( ( ) =>
91- this . #serializer. serialize ( this . #router. routerState . snapshot )
92- ) ,
93- takeUntilDestroyed ( )
94- )
95- . subscribe ( ( routerState ) => {
96- patchState ( this , { routerState } ) ;
97- } ) ;
98- }
99-
100- selectQueryParam (
101- param : string
102- ) : Signal < string | readonly string [ ] | undefined > {
103- return computed ( ( ) => this . queryParams ( ) [ param ] ) ;
104- }
105-
106- selectRouteDataParam ( key : string ) : Signal < unknown > {
107- return computed ( ( ) => this . routeData ( ) [ key ] ) ;
108- }
109-
110- selectRouteParam ( param : string ) : Signal < string | undefined > {
111- return computed ( ( ) => this . routeParams ( ) [ param ] ) ;
112- }
113-
114- selectRouterEvents < TAcceptedRouterEvents extends Type < RouterEvent > [ ] > (
115- ...acceptedEventTypes : [ ...TAcceptedRouterEvents ]
116- ) : Observable < InstanceType < TAcceptedRouterEvents [ number ] > > {
117- return this . #router. events . pipe (
118- filterRouterEvents ( ...acceptedEventTypes )
119- ) as Observable < InstanceType < TAcceptedRouterEvents [ number ] > > ;
120- }
121- }
51+ export const GlobalRouterSignalStore : Type < RouterSignalStore > = signalStore (
52+ withState ( ( ) => inject ( initialGlobalRouterSignalStateToken ) ) ,
53+ withComputed ( ( { _routerState } ) => ( {
54+ _rootRoute : computed (
55+ ( ) : MinimalActivatedRouteSnapshot => _routerState ( ) . root
56+ ) ,
57+ } ) ) ,
58+ withComputed ( ( { _rootRoute } ) => ( {
59+ currentRoute : computed ( ( ) : MinimalActivatedRouteSnapshot => {
60+ let route = _rootRoute ( ) ;
61+
62+ while ( route . firstChild ) {
63+ route = route . firstChild ;
64+ }
65+
66+ return route ;
67+ } ) ,
68+ } ) ) ,
69+ withComputed ( ( { _rootRoute, _routerState, currentRoute } ) => ( {
70+ fragment : computed ( ( ) : string | null => _rootRoute ( ) . fragment ) ,
71+ queryParams : computed (
72+ ( ) : InternalStrictQueryParams => _rootRoute ( ) . queryParams
73+ ) ,
74+ routeData : computed ( ( ) : InternalStrictRouteData => currentRoute ( ) . data ) ,
75+ routeParams : computed (
76+ ( ) : InternalStrictRouteParams => currentRoute ( ) . params
77+ ) ,
78+ title : computed ( ( ) : string | undefined => currentRoute ( ) . title ) ,
79+ url : computed ( ( ) : string => _routerState ( ) . url ) ,
80+ } ) ) ,
81+ withMethods ( ( store , router = inject ( Router ) ) => ( {
82+ selectQueryParam (
83+ param : string
84+ ) : Signal < string | readonly string [ ] | undefined > {
85+ return computed ( ( ) => store . queryParams ( ) [ param ] ) ;
86+ } ,
87+ selectRouteDataParam ( key : string ) : Signal < unknown > {
88+ return computed ( ( ) => store . routeData ( ) [ key ] ) ;
89+ } ,
90+ selectRouteParam ( param : string ) : Signal < string | undefined > {
91+ return computed ( ( ) => store . routeParams ( ) [ param ] ) ;
92+ } ,
93+ selectRouterEvents < TAcceptedRouterEvents extends Type < RouterEvent > [ ] > (
94+ ...acceptedEventTypes : [ ...TAcceptedRouterEvents ]
95+ ) : Observable < InstanceType < TAcceptedRouterEvents [ number ] > > {
96+ return router . events . pipe (
97+ filterRouterEvents ( ...acceptedEventTypes )
98+ ) as Observable < InstanceType < TAcceptedRouterEvents [ number ] > > ;
99+ } ,
100+ } ) ) ,
101+ withHooks ( {
102+ onInit (
103+ store ,
104+ router = inject ( Router ) ,
105+ serializer = inject ( MinimalRouterStateSerializer )
106+ ) : void {
107+ store
108+ . selectRouterEvents (
109+ NavigationStart ,
110+ RoutesRecognized ,
111+ NavigationEnd ,
112+ NavigationCancel ,
113+ NavigationError
114+ )
115+ . pipe (
116+ map ( ( ) => serializer . serialize ( router . routerState . snapshot ) ) ,
117+ takeUntilDestroyed ( )
118+ )
119+ . subscribe ( ( routerState ) =>
120+ patchState ( store , { _routerState : routerState } )
121+ ) ;
122+ } ,
123+ } )
124+ ) ;
0 commit comments