@@ -14,7 +14,7 @@ import {catchError, defaultIfEmpty, filter, finalize, map, switchMap, take, tap}
1414import { createRouterState } from './create_router_state' ;
1515import { createUrlTree } from './create_url_tree' ;
1616import { RuntimeErrorCode } from './errors' ;
17- import { Event , GuardsCheckEnd , GuardsCheckStart , NavigationCancel , NavigationCancellationCode , NavigationEnd , NavigationError , NavigationStart , NavigationTrigger , ResolveEnd , ResolveStart , RouteConfigLoadEnd , RouteConfigLoadStart , RoutesRecognized } from './events' ;
17+ import { Event , GuardsCheckEnd , GuardsCheckStart , NavigationCancel , NavigationCancellationCode , NavigationEnd , NavigationError , NavigationSkipped , NavigationSkippedCode , NavigationStart , NavigationTrigger , ResolveEnd , ResolveStart , RouteConfigLoadEnd , RouteConfigLoadStart , RoutesRecognized } from './events' ;
1818import { NavigationBehaviorOptions , QueryParamsHandling , Route , Routes } from './models' ;
1919import { isNavigationCancelingError , isRedirectingNavigationCancelingError , redirectingNavigationError } from './navigation_canceling_error' ;
2020import { activateRoutes } from './operators/activate_routes' ;
@@ -671,12 +671,21 @@ export class Router {
671671 // matching. If this is not the case, assume something went wrong and
672672 // try processing the URL again.
673673 browserUrlTree !== this . currentUrlTree . toString ( ) ;
674- const processCurrentUrl =
675- ( this . onSameUrlNavigation === 'reload' ? true : urlTransition ) &&
676- this . urlHandlingStrategy . shouldProcessUrl ( t . rawUrl ) ;
677674
675+ if ( ! urlTransition && this . onSameUrlNavigation !== 'reload' ) {
676+ const reason = NG_DEV_MODE ?
677+ `Navigation to ${
678+ t . rawUrl } was ignored because it is the same as the current Router URL.` :
679+ '' ;
680+ this . triggerEvent ( new NavigationSkipped (
681+ t . id , this . serializeUrl ( overallTransitionState . rawUrl ) , reason ,
682+ NavigationSkippedCode . IgnoredSameUrlNavigation ) ) ;
683+ this . rawUrlTree = t . rawUrl ;
684+ t . resolve ( null ) ;
685+ return EMPTY ;
686+ }
678687
679- if ( processCurrentUrl ) {
688+ if ( this . urlHandlingStrategy . shouldProcessUrl ( t . rawUrl ) ) {
680689 // If the source of the navigation is from a browser event, the URL is
681690 // already updated. We already need to sync the internal state.
682691 if ( isBrowserTriggeredNavigation ( t . source ) ) {
@@ -736,37 +745,44 @@ export class Router {
736745 this . serializeUrl ( t . urlAfterRedirects ! ) , t . targetSnapshot ! ) ;
737746 eventsSubject . next ( routesRecognized ) ;
738747 } ) ) ;
748+ } else if (
749+ urlTransition &&
750+ this . urlHandlingStrategy . shouldProcessUrl ( this . rawUrlTree ) ) {
751+ // When the current URL shouldn't be processed, but the previous one
752+ // was, we handle this by navigating from the current URL to an empty
753+ // state so deactivate guards can run.
754+ const { id, extractedUrl, source, restoredState, extras} = t ;
755+ const navStart = new NavigationStart (
756+ id , this . serializeUrl ( extractedUrl ) , source , restoredState ) ;
757+ eventsSubject . next ( navStart ) ;
758+ const targetSnapshot =
759+ createEmptyState ( extractedUrl , this . rootComponentType ) . snapshot ;
760+
761+ overallTransitionState = {
762+ ...t ,
763+ targetSnapshot,
764+ urlAfterRedirects : extractedUrl ,
765+ extras : { ...extras , skipLocationChange : false , replaceUrl : false } ,
766+ } ;
767+ return of ( overallTransitionState ) ;
739768 } else {
740- const processPreviousUrl = urlTransition && this . rawUrlTree &&
741- this . urlHandlingStrategy . shouldProcessUrl ( this . rawUrlTree ) ;
742- /* When the current URL shouldn't be processed, but the previous one
743- * was, we handle this "error condition" by navigating to the
744- * previously successful URL, but leaving the URL intact.*/
745- if ( processPreviousUrl ) {
746- const { id, extractedUrl, source, restoredState, extras} = t ;
747- const navStart = new NavigationStart (
748- id , this . serializeUrl ( extractedUrl ) , source , restoredState ) ;
749- eventsSubject . next ( navStart ) ;
750- const targetSnapshot =
751- createEmptyState ( extractedUrl , this . rootComponentType ) . snapshot ;
752-
753- overallTransitionState = {
754- ...t ,
755- targetSnapshot,
756- urlAfterRedirects : extractedUrl ,
757- extras : { ...extras , skipLocationChange : false , replaceUrl : false } ,
758- } ;
759- return of ( overallTransitionState ) ;
760- } else {
761- /* When neither the current or previous URL can be processed, do
762- * nothing other than update router's internal reference to the
763- * current "settled" URL. This way the next navigation will be coming
764- * from the current URL in the browser.
765- */
766- this . rawUrlTree = t . rawUrl ;
767- t . resolve ( null ) ;
768- return EMPTY ;
769- }
769+ /* When neither the current or previous URL can be processed, do
770+ * nothing other than update router's internal reference to the
771+ * current "settled" URL. This way the next navigation will be coming
772+ * from the current URL in the browser.
773+ */
774+ const reason = NG_DEV_MODE ?
775+ `Navigation was ignored because the UrlHandlingStrategy` +
776+ ` indicated neither the current URL ${
777+ this . rawUrlTree } nor target URL ${
778+ t . rawUrl } should be processed.` :
779+ '' ;
780+ this . triggerEvent ( new NavigationSkipped (
781+ t . id , this . serializeUrl ( overallTransitionState . extractedUrl ) ,
782+ reason , NavigationSkippedCode . IgnoredByUrlHandlingStrategy ) ) ;
783+ this . rawUrlTree = t . rawUrl ;
784+ t . resolve ( null ) ;
785+ return EMPTY ;
770786 }
771787 } ) ,
772788
0 commit comments