Skip to content

Commit 0b82192

Browse files
committed
feat: add WIP RouterHistoryStore#nextUrl$ property
1 parent 412324c commit 0b82192

File tree

2 files changed

+169
-3
lines changed

2 files changed

+169
-3
lines changed

packages/router-component-store/src/lib/router-history-store/router-history.store.spec.ts

+137-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ function createTestComponent(name: string, selector: string) {
3030
>&lt; Back</a
3131
>
3232
33+
<a
34+
id="forward-link"
35+
*ngIf="routerHistory.nextUrl$ | async as nextUrl"
36+
[href]="nextUrl"
37+
(click)="onNext($event)"
38+
>&gt; Next</a
39+
>
40+
3341
<a id="home-link" routerLink="/">Home</a>
3442
<a id="about-link" routerLink="about">About</a>
3543
<a id="company-link" routerLink="company">Company</a>
@@ -45,6 +53,11 @@ class TestAppComponent {
4553
event.preventDefault();
4654
this.routerHistory.onNavigateBack();
4755
}
56+
57+
onNext(event: MouseEvent) {
58+
event.preventDefault();
59+
this.routerHistory.onNavigateForward();
60+
}
4861
}
4962

5063
describe(RouterHistoryStore.name, () => {
@@ -98,55 +111,176 @@ describe(RouterHistoryStore.name, () => {
98111
}
99112

100113
it('the URLs behave like the History API when navigating using links', async () => {
101-
expect.assertions(2);
114+
expect.assertions(3);
102115

103116
const { click, routerHistory } = await setup();
104117

105118
// At Home
119+
// Previous: None
120+
// Next: None
106121
await click('#about-link');
107122
// At About
123+
// Previous: Home
124+
// Next: None
108125
await click('#company-link');
109126
// At Company
127+
// Previous: About
128+
// Next: None
110129
await click('#products-link');
111130
// At Products
131+
// Previous: Company
132+
// Next: None
112133

113134
expect(await firstValueFrom(routerHistory.currentUrl$)).toBe('/products');
114135
expect(await firstValueFrom(routerHistory.previousUrl$)).toBe('/company');
136+
expect(await firstValueFrom(routerHistory.nextUrl$)).toBe(undefined);
115137
});
116138

117139
it('the URLs behave like the History API when navigating back', async () => {
118-
expect.assertions(2);
140+
expect.assertions(3);
141+
142+
const { click, routerHistory } = await setup();
143+
144+
// At Home
145+
// Previous: None
146+
// Next: None
147+
await click('#about-link');
148+
// At About
149+
// Previous: Home
150+
// Next: None
151+
await click('#company-link');
152+
// At Company
153+
// Previous: About
154+
// Next: None
155+
await click('#back-link');
156+
// At About
157+
// Previous: Home
158+
// Next: Company
159+
160+
expect(await firstValueFrom(routerHistory.currentUrl$)).toBe('/about');
161+
expect(await firstValueFrom(routerHistory.previousUrl$)).toBe('/home');
162+
expect(await firstValueFrom(routerHistory.nextUrl$)).toBe('/company');
163+
});
164+
165+
it('the URLs behave like the History API when navigating back twice', async () => {
166+
expect.assertions(3);
167+
168+
const { click, routerHistory } = await setup();
169+
170+
// At Home
171+
// Previous: None
172+
// Next: None
173+
await click('#about-link');
174+
// At About
175+
// Previous: Home
176+
// Next: None
177+
await click('#company-link');
178+
// At Company
179+
// Previous: About
180+
// Next: None
181+
await click('#back-link');
182+
// At About
183+
// Previous: Home
184+
// Next: Company
185+
await click('#back-link');
186+
// At Home
187+
// Previous: None
188+
// Next: About
189+
190+
expect(await firstValueFrom(routerHistory.currentUrl$)).toBe('/home');
191+
expect(await firstValueFrom(routerHistory.previousUrl$)).toBe(undefined);
192+
expect(await firstValueFrom(routerHistory.nextUrl$)).toBe('/about');
193+
});
194+
195+
it('the URLs behave like the History API when navigating back twice then forward', async () => {
196+
expect.assertions(3);
119197

120198
const { click, routerHistory } = await setup();
121199

122200
// At Home
201+
// Previous: None
202+
// Next: None
123203
await click('#about-link');
124204
// At About
205+
// Previous: Home
206+
// Next: None
125207
await click('#company-link');
126208
// At Company
209+
// Previous: About
210+
// Next: None
127211
await click('#back-link');
128212
// At About
213+
// Previous: Home
214+
// Next: Company
215+
await click('#back-link');
216+
// At Home
217+
// Previous: None
218+
// Next: About
219+
await click('#forward-link');
220+
// At About
221+
// Previous: Home
222+
// Next: Company
129223

130224
expect(await firstValueFrom(routerHistory.currentUrl$)).toBe('/about');
131225
expect(await firstValueFrom(routerHistory.previousUrl$)).toBe('/home');
226+
expect(await firstValueFrom(routerHistory.nextUrl$)).toBe('/company');
132227
});
133228

134229
it('the URLs behave like the History API when navigating back then using links', async () => {
135-
expect.assertions(2);
230+
expect.assertions(3);
136231

137232
const { click, routerHistory } = await setup();
138233

139234
// At Home
235+
// Previous: None
236+
// Next: None
140237
await click('#about-link');
141238
// At About
239+
// Previous: Home
240+
// Next: None
142241
await click('#company-link');
143242
// At Company
243+
// Previous: About
244+
// Next: None
144245
await click('#back-link');
145246
// At About
247+
// Previous: Home
248+
// Next: Company
146249
await click('#products-link');
147250
// At Products
251+
// Previous: About
252+
// Next: None
148253

149254
expect(await firstValueFrom(routerHistory.currentUrl$)).toBe('/products');
150255
expect(await firstValueFrom(routerHistory.previousUrl$)).toBe('/about');
256+
expect(await firstValueFrom(routerHistory.nextUrl$)).toBe(undefined);
257+
});
258+
259+
it('the URLs behave like the History API when navigating back then forward', async () => {
260+
expect.assertions(3);
261+
262+
const { click, routerHistory } = await setup();
263+
264+
// At Home
265+
await click('#about-link');
266+
// At About
267+
// Previous: Home
268+
// Next: None
269+
await click('#company-link');
270+
// At Company
271+
// Previous: About
272+
// Next: None
273+
await click('#back-link');
274+
// At About
275+
// Previous: Home
276+
// Next: Company
277+
await click('#forward-link');
278+
// At Company
279+
// Previous: About
280+
// Next: None
281+
282+
expect(await firstValueFrom(routerHistory.currentUrl$)).toBe('/company');
283+
expect(await firstValueFrom(routerHistory.previousUrl$)).toBe('/about');
284+
expect(await firstValueFrom(routerHistory.nextUrl$)).toBe(undefined);
151285
});
152286
});

packages/router-component-store/src/lib/router-history-store/router-history.store.ts

+32
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,38 @@ export class RouterHistoryStore extends ComponentStore<RouterHistoryState> {
127127
this.#latestRouterNavigatedSequence$,
128128
([, navigationEnd]) => navigationEnd.urlAfterRedirects
129129
);
130+
/**
131+
* The next URL when taking `popstate` events into account.
132+
*
133+
* `undefined` is emitted when the current navigation is the last in the
134+
* navigation history.
135+
*/
136+
nextUrl$: Observable<string | undefined> = this.select(
137+
this.#history$,
138+
this.#maxNavigatedId$,
139+
(history, maxNavigatedId) => {
140+
if (maxNavigatedId === 1) {
141+
return undefined;
142+
}
143+
144+
const [sourceNavigationStart] = this.#findSourceNavigatedSequence(
145+
maxNavigatedId,
146+
history
147+
);
148+
149+
if (sourceNavigationStart.id === maxNavigatedId) {
150+
return undefined;
151+
}
152+
153+
const nextNavigationId = sourceNavigationStart.id + 1;
154+
const [, nextNavigationEnd] = this.#findSourceNavigatedSequence(
155+
nextNavigationId,
156+
history
157+
);
158+
159+
return nextNavigationEnd.urlAfterRedirects;
160+
}
161+
);
130162
/**
131163
* The previous URL when taking `popstate` events into account.
132164
*

0 commit comments

Comments
 (0)