Skip to content

Commit 6120835

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

File tree

2 files changed

+99
-3
lines changed

2 files changed

+99
-3
lines changed

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

Lines changed: 67 additions & 3 deletions
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,7 +111,7 @@ 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

@@ -112,10 +125,11 @@ describe(RouterHistoryStore.name, () => {
112125

113126
expect(await firstValueFrom(routerHistory.currentUrl$)).toBe('/products');
114127
expect(await firstValueFrom(routerHistory.previousUrl$)).toBe('/company');
128+
expect(await firstValueFrom(routerHistory.nextUrl$)).toBe(undefined);
115129
});
116130

117131
it('the URLs behave like the History API when navigating back', async () => {
118-
expect.assertions(2);
132+
expect.assertions(3);
119133

120134
const { click, routerHistory } = await setup();
121135

@@ -129,10 +143,31 @@ describe(RouterHistoryStore.name, () => {
129143

130144
expect(await firstValueFrom(routerHistory.currentUrl$)).toBe('/about');
131145
expect(await firstValueFrom(routerHistory.previousUrl$)).toBe('/home');
146+
expect(await firstValueFrom(routerHistory.nextUrl$)).toBe('/company');
147+
});
148+
149+
it('the URLs behave like the History API when navigating back twice', async () => {
150+
expect.assertions(3);
151+
152+
const { click, routerHistory } = await setup();
153+
154+
// At Home
155+
await click('#about-link');
156+
// At About
157+
await click('#company-link');
158+
// At Company
159+
await click('#back-link');
160+
// At About
161+
await click('#back-link');
162+
// At Home
163+
164+
expect(await firstValueFrom(routerHistory.currentUrl$)).toBe('/home');
165+
expect(await firstValueFrom(routerHistory.previousUrl$)).toBe(undefined);
166+
expect(await firstValueFrom(routerHistory.nextUrl$)).toBe('/about');
132167
});
133168

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

137172
const { click, routerHistory } = await setup();
138173

@@ -148,5 +183,34 @@ describe(RouterHistoryStore.name, () => {
148183

149184
expect(await firstValueFrom(routerHistory.currentUrl$)).toBe('/products');
150185
expect(await firstValueFrom(routerHistory.previousUrl$)).toBe('/about');
186+
expect(await firstValueFrom(routerHistory.nextUrl$)).toBe(undefined);
187+
});
188+
189+
it('the URLs behave like the History API when navigating back then forward', async () => {
190+
expect.assertions(3);
191+
192+
const { click, routerHistory } = await setup();
193+
194+
// At Home
195+
await click('#about-link');
196+
// At About
197+
// Previous: Home
198+
// Next: None
199+
await click('#company-link');
200+
// At Company
201+
// Previous: About
202+
// Next: None
203+
await click('#back-link');
204+
// At About
205+
// Previous: Home
206+
// Next: Company
207+
await click('#forward-link');
208+
// At Company
209+
// Previous: About
210+
// Next: None
211+
212+
expect(await firstValueFrom(routerHistory.currentUrl$)).toBe('/company');
213+
expect(await firstValueFrom(routerHistory.previousUrl$)).toBe('/about');
214+
expect(await firstValueFrom(routerHistory.nextUrl$)).toBe(undefined);
151215
});
152216
});

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

Lines changed: 32 additions & 0 deletions
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)