@@ -7,31 +7,24 @@ import {
7
7
} from '@angular/core' ;
8
8
import { NavigationEnd , NavigationStart , Router } from '@angular/router' ;
9
9
import { ComponentStore , provideComponentStore } from '@ngrx/component-store' ;
10
- import { filter , Observable } from 'rxjs' ;
10
+ import { filter , map , Observable , switchMap , take } from 'rxjs' ;
11
+ import { filterRouterEvents } from '../filter-router-event.operator' ;
11
12
12
13
interface RouterHistoryState {
13
14
/**
14
- * The history of all router navigation sequences.
15
+ * The history of all router navigated sequences.
15
16
*
16
17
* The key is the navigation ID.
17
18
*/
18
- readonly history : RouterNavigationHistory ;
19
+ readonly history : RouterNavigatedHistory ;
20
+ /**
21
+ * The ID of the most recent router navigated sequence events.
22
+ */
23
+ readonly maxNavigatedId ?: number ;
19
24
}
20
25
21
26
type RouterNavigatedSequence = readonly [ NavigationStart , NavigationEnd ] ;
22
- type RouterNavigationHistory = Record < number , RouterNavigationSequence > ;
23
- type RouterNavigationSequence = RouterRequestSequence | RouterNavigatedSequence ;
24
- type RouterRequestSequence = readonly [ NavigationStart ] ;
25
-
26
- function isRouterNavigatedSequence (
27
- sequence : RouterNavigationSequence
28
- ) : sequence is RouterNavigatedSequence {
29
- return (
30
- sequence . length === 2 &&
31
- sequence [ 0 ] instanceof NavigationStart &&
32
- sequence [ 1 ] instanceof NavigationEnd
33
- ) ;
34
- }
27
+ type RouterNavigatedHistory = Readonly < Record < number , RouterNavigatedSequence > > ;
35
28
36
29
/**
37
30
* Provide and initialize the `RouterHistoryStore`.
@@ -56,44 +49,48 @@ export class RouterHistoryStore extends ComponentStore<RouterHistoryState> {
56
49
#history$ = this . select ( ( state ) => state . history ) . pipe (
57
50
filter ( ( history ) => Object . keys ( history ) . length > 0 )
58
51
) ;
52
+ #maxNavigatedId$ = this . select ( ( state ) => state . maxNavigatedId ) . pipe (
53
+ filter (
54
+ ( maxNavigatedId ) : maxNavigatedId is number => maxNavigatedId !== undefined
55
+ )
56
+ ) ;
59
57
/**
60
58
* All `NavigationEnd` events.
61
59
*/
62
60
#navigationEnd$: Observable < NavigationEnd > = this . #router. events . pipe (
63
- filter ( ( event ) : event is NavigationEnd => event instanceof NavigationEnd )
61
+ filterRouterEvents ( NavigationEnd )
64
62
) ;
65
63
/**
66
64
* All `NavigationStart` events.
67
65
*/
68
66
#navigationStart$: Observable < NavigationStart > = this . #router. events . pipe (
69
- filter (
70
- ( event ) : event is NavigationStart => event instanceof NavigationStart
71
- )
67
+ filterRouterEvents ( NavigationStart )
72
68
) ;
73
-
74
69
/**
75
- * The navigation ID of the most recent router navigated sequence .
70
+ * All router navigated sequences, that is `NavigationStart` followed by `NavigationEnd` .
76
71
*/
77
- #maxRouterNavigatedSequenceId$ = this . select (
78
- this . #history$. pipe ( filter ( this . #selectHasRouterNavigated) ) ,
79
- ( history ) =>
80
- Number (
81
- // This callback is only triggered when at least one navigation has
82
- // completed
83
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
84
- Object . entries ( history )
85
- . reverse ( )
86
- . find ( ( [ , navigation ] ) => navigation . length === 2 ) ! [ 0 ]
72
+ #routerNavigated$: Observable < RouterNavigatedSequence > =
73
+ this . #navigationStart$. pipe (
74
+ switchMap ( ( navigationStart ) =>
75
+ this . #navigationEnd$. pipe (
76
+ filter ( ( navigationEnd ) => navigationEnd . id === navigationStart . id ) ,
77
+ take ( 1 ) ,
78
+ map (
79
+ ( navigationEnd ) =>
80
+ [ navigationStart , navigationEnd ] as RouterNavigatedSequence
81
+ )
82
+ )
87
83
)
88
- ) ;
84
+ ) ;
85
+
89
86
/**
90
87
* The most recent completed navigation.
91
88
*/
92
89
#latestRouterNavigatedSequence$ = this . select (
93
- this . #maxRouterNavigatedSequenceId $,
90
+ this . #maxNavigatedId $,
94
91
this . #history$,
95
- ( maxRouterNavigatedSequenceId , history ) =>
96
- history [ maxRouterNavigatedSequenceId ] as RouterNavigatedSequence ,
92
+ ( maxNavigatedId , history ) =>
93
+ history [ maxNavigatedId ] as RouterNavigatedSequence ,
97
94
{
98
95
debounce : true ,
99
96
}
@@ -104,7 +101,7 @@ export class RouterHistoryStore extends ComponentStore<RouterHistoryState> {
104
101
*/
105
102
currentUrl$ : Observable < string > = this . select (
106
103
this . #latestRouterNavigatedSequence$,
107
- ( [ , end ] ) => end . urlAfterRedirects
104
+ ( [ , navigationEnd ] ) => navigationEnd . urlAfterRedirects
108
105
) ;
109
106
/**
110
107
* The previous URL when taking `popstate` events into account.
@@ -114,28 +111,28 @@ export class RouterHistoryStore extends ComponentStore<RouterHistoryState> {
114
111
*/
115
112
previousUrl$ : Observable < string | undefined > = this . select (
116
113
this . #history$,
117
- this . #maxRouterNavigatedSequenceId $,
118
- ( history , maxCompletedNavigationId ) => {
119
- if ( maxCompletedNavigationId === 1 ) {
114
+ this . #maxNavigatedId $,
115
+ ( history , maxNavigatedId ) => {
116
+ if ( maxNavigatedId === 1 ) {
120
117
return undefined ;
121
118
}
122
119
123
- const [ completedNavigationSourceStart ] = this . #getNavigationSource(
124
- maxCompletedNavigationId ,
120
+ const [ sourceNavigationStart ] = this . #getNavigationSource(
121
+ maxNavigatedId ,
125
122
history
126
123
) ;
127
124
128
- if ( completedNavigationSourceStart . id === 1 ) {
125
+ if ( sourceNavigationStart . id === 1 ) {
129
126
return undefined ;
130
127
}
131
128
132
- const previousNavigationId = completedNavigationSourceStart . id - 1 ;
133
- const [ , previousNavigationSourceEnd ] = this . #getNavigationSource(
129
+ const previousNavigationId = sourceNavigationStart . id - 1 ;
130
+ const [ , previousNavigationEnd ] = this . #getNavigationSource(
134
131
previousNavigationId ,
135
132
history
136
133
) ;
137
134
138
- return previousNavigationSourceEnd . urlAfterRedirects ;
135
+ return previousNavigationEnd . urlAfterRedirects ;
139
136
} ,
140
137
{
141
138
debounce : true ,
@@ -145,34 +142,28 @@ export class RouterHistoryStore extends ComponentStore<RouterHistoryState> {
145
142
constructor ( ) {
146
143
super ( initialState ) ;
147
144
148
- this . #addNavigationStart( this . #navigationStart$) ;
149
- this . #addNavigationEnd( this . #navigationEnd$) ;
145
+ this . #addRouterNavigatedSequence( this . #routerNavigated$) ;
150
146
}
151
147
152
148
/**
153
- * Add a `NavigationEnd` event to the navigation history.
154
- */
155
- #addNavigationEnd = this . updater < NavigationEnd > (
156
- ( state , event ) : RouterHistoryState => ( {
157
- ...state ,
158
- history : {
159
- ...state . history ,
160
- [ event . id ] : [ state . history [ event . id ] [ 0 ] , event ] ,
161
- } ,
162
- } )
163
- ) ;
164
-
165
- /**
166
- * Add a `NavigationStart` event to the navigation history.
149
+ * Add a router navigated sequence to the router navigated history.
167
150
*/
168
- #addNavigationStart = this . updater < NavigationStart > (
169
- ( state , event ) : RouterHistoryState => ( {
170
- ...state ,
171
- history : {
172
- ...state . history ,
173
- [ event . id ] : [ event ] ,
174
- } ,
175
- } )
151
+ #addRouterNavigatedSequence = this . updater < RouterNavigatedSequence > (
152
+ ( state , routerNavigated ) : RouterHistoryState => {
153
+ const [ { id : navigationId } ] = routerNavigated ;
154
+
155
+ return {
156
+ ...state ,
157
+ history : {
158
+ ...state . history ,
159
+ [ navigationId ] : routerNavigated ,
160
+ } ,
161
+ maxNavigatedId :
162
+ navigationId > ( state . maxNavigatedId ?? 0 )
163
+ ? navigationId
164
+ : state . maxNavigatedId ,
165
+ } ;
166
+ }
176
167
) ;
177
168
178
169
/**
@@ -187,7 +178,7 @@ export class RouterHistoryStore extends ComponentStore<RouterHistoryState> {
187
178
*/
188
179
#getNavigationSource(
189
180
navigationId : number ,
190
- history : RouterNavigationHistory
181
+ history : RouterNavigatedHistory
191
182
) : RouterNavigatedSequence {
192
183
let navigation = history [ navigationId ] ;
193
184
@@ -201,14 +192,7 @@ export class RouterHistoryStore extends ComponentStore<RouterHistoryState> {
201
192
] ;
202
193
}
203
194
204
- return navigation as RouterNavigatedSequence ;
205
- }
206
-
207
- #selectHasRouterNavigated( history : RouterNavigationHistory ) : boolean {
208
- const firstNavigationId = 1 ;
209
- const firstNavigation = history [ firstNavigationId ] ?? [ ] ;
210
-
211
- return isRouterNavigatedSequence ( firstNavigation ) ;
195
+ return navigation ;
212
196
}
213
197
}
214
198
0 commit comments