fix(router): Prevent dangling promise rejections from internal navigations (#60162)

Though the plan is to change the default behavior or the router to
instead resolve the navigation promise with `false` to match all other
failed navigations, we should still prevent dangling promise rejections
from navigations triggered internally when developers opt to use the old
(current) behavior.

PR Close #60162
This commit is contained in:
Andrew Scott 2025-02-28 12:12:48 -08:00 committed by Andrew Kushnir
parent 4c22e65719
commit 219f41d049
2 changed files with 13 additions and 2 deletions

View file

@ -21,6 +21,8 @@ import {
ɵRuntimeError as RuntimeError,
SimpleChanges,
ɵɵsanitizeUrlOrResourceUrl,
ɵINTERNAL_APPLICATION_ERROR_HANDLER,
inject,
} from '@angular/core';
import {Subject, Subscription} from 'rxjs';
@ -202,6 +204,8 @@ export class RouterLink implements OnChanges, OnDestroy {
/** @internal */
onChanges = new Subject<RouterLink>();
private readonly applicationErrorHandler = inject(ɵINTERNAL_APPLICATION_ERROR_HANDLER);
constructor(
private router: Router,
private route: ActivatedRoute,
@ -349,7 +353,9 @@ export class RouterLink implements OnChanges, OnDestroy {
state: this.state,
info: this.info,
};
this.router.navigateByUrl(urlTree, extras);
this.router.navigateByUrl(urlTree, extras).catch((e) => {
this.applicationErrorHandler(e);
});
// Return `false` for `<a>` elements to prevent default action
// and cancel the native behavior, since the navigation is handled

View file

@ -14,6 +14,8 @@ import {
ɵConsole as Console,
ɵPendingTasksInternal as PendingTasks,
ɵRuntimeError as RuntimeError,
ɵINTERNAL_APPLICATION_ERROR_HANDLER,
EnvironmentInjector,
} from '@angular/core';
import {Observable, Subject, Subscription, SubscriptionLike} from 'rxjs';
@ -114,6 +116,7 @@ export class Router {
private readonly urlSerializer = inject(UrlSerializer);
private readonly location = inject(Location);
private readonly urlHandlingStrategy = inject(UrlHandlingStrategy);
private readonly injector = inject(EnvironmentInjector);
/**
* The private `Subject` type for the public events exposed in the getter. This is used internally
@ -324,7 +327,9 @@ export class Router {
}
const urlTree = this.parseUrl(url);
this.scheduleNavigation(urlTree, source, restoredState, extras);
this.scheduleNavigation(urlTree, source, restoredState, extras).catch((e) => {
this.injector.get(ɵINTERNAL_APPLICATION_ERROR_HANDLER)(e);
});
}
/** The current URL. */