@@ -12,7 +12,7 @@ import {BehaviorSubject, Observable, of, SubscriptionLike} from 'rxjs';
1212
1313import { CreateUrlTreeStrategy } from './create_url_tree_strategy' ;
1414import { RuntimeErrorCode } from './errors' ;
15- import { Event , NavigationTrigger } from './events' ;
15+ import { Event , IMPERATIVE_NAVIGATION , NavigationTrigger } from './events' ;
1616import { NavigationBehaviorOptions , OnSameUrlNavigation , Routes } from './models' ;
1717import { Navigation , NavigationExtras , NavigationTransition , NavigationTransitions , RestoredState , UrlCreationOptions } from './navigation_transition' ;
1818import { TitleStrategy } from './page_title_strategy' ;
@@ -353,7 +353,8 @@ export class Router {
353353 initialNavigation ( ) : void {
354354 this . setUpLocationChangeListener ( ) ;
355355 if ( ! this . navigationTransitions . hasRequestedNavigation ) {
356- this . navigateByUrl ( this . location . path ( true ) , { replaceUrl : true } ) ;
356+ const state = this . location . getState ( ) as RestoredState ;
357+ this . navigateToSyncWithBrowser ( this . location . path ( true ) , IMPERATIVE_NAVIGATION , state ) ;
357358 }
358359 }
359360
@@ -373,37 +374,49 @@ export class Router {
373374 // The `setTimeout` was added in #12160 and is likely to support Angular/AngularJS
374375 // hybrid apps.
375376 setTimeout ( ( ) => {
376- const extras : NavigationExtras = { replaceUrl : true } ;
377-
378- // TODO: restoredState should always include the entire state, regardless
379- // of navigationId. This requires a breaking change to update the type on
380- // NavigationStart’s restoredState, which currently requires navigationId
381- // to always be present. The Router used to only restore history state if
382- // a navigationId was present.
383-
384- // The stored navigationId is used by the RouterScroller to retrieve the scroll
385- // position for the page.
386- const restoredState = event . state ?. navigationId ? event . state : null ;
387-
388- // Separate to NavigationStart.restoredState, we must also restore the state to
389- // history.state and generate a new navigationId, since it will be overwritten
390- if ( event . state ) {
391- const stateCopy = { ...event . state } as Partial < RestoredState > ;
392- delete stateCopy . navigationId ;
393- delete stateCopy . ɵrouterPageId ;
394- if ( Object . keys ( stateCopy ) . length !== 0 ) {
395- extras . state = stateCopy ;
396- }
397- }
398-
399- const urlTree = this . parseUrl ( event [ 'url' ] ! ) ;
400- this . scheduleNavigation ( urlTree , source , restoredState , extras ) ;
377+ this . navigateToSyncWithBrowser ( event [ 'url' ] ! , source , event . state ) ;
401378 } , 0 ) ;
402379 }
403380 } ) ;
404381 }
405382 }
406383
384+ /**
385+ * Schedules a router navigation to synchronize Router state with the browser state.
386+ *
387+ * This is done as a response to a popstate event and the initial navigation. These
388+ * two scenarios represent times when the browser URL/state has been updated and
389+ * the Router needs to respond to ensure its internal state matches.
390+ */
391+ private navigateToSyncWithBrowser (
392+ url : string , source : NavigationTrigger , state : RestoredState | undefined ) {
393+ const extras : NavigationExtras = { replaceUrl : true } ;
394+
395+ // TODO: restoredState should always include the entire state, regardless
396+ // of navigationId. This requires a breaking change to update the type on
397+ // NavigationStart’s restoredState, which currently requires navigationId
398+ // to always be present. The Router used to only restore history state if
399+ // a navigationId was present.
400+
401+ // The stored navigationId is used by the RouterScroller to retrieve the scroll
402+ // position for the page.
403+ const restoredState = state ?. navigationId ? state : null ;
404+
405+ // Separate to NavigationStart.restoredState, we must also restore the state to
406+ // history.state and generate a new navigationId, since it will be overwritten
407+ if ( state ) {
408+ const stateCopy = { ...state } as Partial < RestoredState > ;
409+ delete stateCopy . navigationId ;
410+ delete stateCopy . ɵrouterPageId ;
411+ if ( Object . keys ( stateCopy ) . length !== 0 ) {
412+ extras . state = stateCopy ;
413+ }
414+ }
415+
416+ const urlTree = this . parseUrl ( url ) ;
417+ this . scheduleNavigation ( urlTree , source , restoredState , extras ) ;
418+ }
419+
407420 /** The current URL. */
408421 get url ( ) : string {
409422 return this . serializeUrl ( this . currentUrlTree ) ;
@@ -561,7 +574,7 @@ export class Router {
561574 const urlTree = isUrlTree ( url ) ? url : this . parseUrl ( url ) ;
562575 const mergedTree = this . urlHandlingStrategy . merge ( urlTree , this . rawUrlTree ) ;
563576
564- return this . scheduleNavigation ( mergedTree , 'imperative' , null , extras ) ;
577+ return this . scheduleNavigation ( mergedTree , IMPERATIVE_NAVIGATION , null , extras ) ;
565578 }
566579
567580 /**
@@ -686,10 +699,6 @@ export class Router {
686699
687700 let targetPageId : number ;
688701 if ( this . canceledNavigationResolution === 'computed' ) {
689- const isInitialPage = this . currentPageId === 0 ;
690- if ( isInitialPage ) {
691- restoredState = this . location . getState ( ) as RestoredState | null ;
692- }
693702 // If the `ɵrouterPageId` exist in the state then `targetpageId` should have the value of
694703 // `ɵrouterPageId`. This is the case for something like a page refresh where we assign the
695704 // target id to the previously set value for that page.
0 commit comments