Skip to content

Commit 9baefd0

Browse files
atscottdylhunn
authored andcommitted
fix(router): Ensure renavigating in component init works with enabledBlocking (#48063)
The way to complete the `Subject` in a way that is able to be read on the subject properties itself is to call `unsubscribe`: https://github.com/ReactiveX/rxjs/blob/afac3d574323333572987e043adcd0f8d4cff546/src/internal/Subject.ts#L101-L104 This sets the `closed` property to `true` whereas `complete` does not. fixes #48052 PR Close #48063
1 parent 02b9d43 commit 9baefd0

File tree

2 files changed

+54
-3
lines changed

2 files changed

+54
-3
lines changed

packages/router/src/provide_router.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,10 @@ export function getBootstrapListener() {
208208
injector.get(ROUTER_PRELOADER, null, InjectFlags.Optional)?.setUpPreloading();
209209
injector.get(ROUTER_SCROLLER, null, InjectFlags.Optional)?.init();
210210
router.resetRootComponentType(ref.componentTypes[0]);
211-
bootstrapDone.next();
212-
bootstrapDone.complete();
211+
if (!bootstrapDone.closed) {
212+
bootstrapDone.next();
213+
bootstrapDone.unsubscribe();
214+
}
213215
};
214216
}
215217

packages/router/test/bootstrap.spec.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {ApplicationRef, Component, CUSTOM_ELEMENTS_SCHEMA, destroyPlatform, Inje
1111
import {inject} from '@angular/core/testing';
1212
import {BrowserModule} from '@angular/platform-browser';
1313
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
14-
import {NavigationEnd, provideRouter, Resolve, Router, RouterModule, withEnabledBlockingInitialNavigation} from '@angular/router';
14+
import {NavigationEnd, provideRouter, Resolve, Router, RouterModule, RouterOutlet, withEnabledBlockingInitialNavigation} from '@angular/router';
1515

1616
// This is needed, because all files under `packages/` are compiled together as part of the
1717
// [legacy-unit-tests-saucelabs][1] CI job, including the `lib.webworker.d.ts` typings brought in by
@@ -112,6 +112,55 @@ describe('bootstrap', () => {
112112
});
113113
});
114114

115+
it('should finish navigation when initial navigation is enabledBlocking and component renavigates on render',
116+
async () => {
117+
@Component({
118+
template: '',
119+
standalone: true,
120+
})
121+
class Renavigate {
122+
constructor(router: Router) {
123+
router.navigateByUrl('/other');
124+
}
125+
}
126+
@Component({
127+
template: '',
128+
standalone: true,
129+
})
130+
class BlankCmp {
131+
}
132+
133+
let resolveFn: () => void;
134+
const navigationEndPromise = new Promise<void>(r => {
135+
resolveFn = r;
136+
});
137+
138+
@NgModule({
139+
imports: [BrowserModule, RouterOutlet],
140+
declarations: [RootCmp],
141+
bootstrap: [RootCmp],
142+
providers: [
143+
{provide: LocationStrategy, useClass: HashLocationStrategy},
144+
provideRouter(
145+
[{path: '', component: Renavigate}, {path: 'other', component: BlankCmp}],
146+
withEnabledBlockingInitialNavigation())
147+
],
148+
})
149+
class TestModule {
150+
constructor(router: Router) {
151+
router.events.subscribe(e => {
152+
if (e instanceof NavigationEnd) {
153+
resolveFn();
154+
expect(router.url).toEqual('/other');
155+
}
156+
});
157+
}
158+
}
159+
160+
await Promise.all(
161+
[platformBrowserDynamic([]).bootstrapModule(TestModule), navigationEndPromise]);
162+
});
163+
115164
it('should wait for redirect when initialNavigation = enabledBlocking', async () => {
116165
@Injectable({providedIn: 'root'})
117166
class Redirect {

0 commit comments

Comments
 (0)