@@ -12,7 +12,7 @@ import {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' ;
@@ -354,7 +354,8 @@ export class Router {
354354 initialNavigation ( ) : void {
355355 this . setUpLocationChangeListener ( ) ;
356356 if ( ! this . navigationTransitions . hasRequestedNavigation ) {
357- this . navigateByUrl ( this . location . path ( true ) , { replaceUrl : true } ) ;
357+ const state = this . location . getState ( ) as RestoredState ;
358+ this . navigateToSyncWithBrowser ( this . location . path ( true ) , IMPERATIVE_NAVIGATION , state ) ;
358359 }
359360 }
360361
@@ -374,37 +375,49 @@ export class Router {
374375 // The `setTimeout` was added in #12160 and is likely to support Angular/AngularJS
375376 // hybrid apps.
376377 setTimeout ( ( ) => {
377- const extras : NavigationExtras = { replaceUrl : true } ;
378-
379- // TODO: restoredState should always include the entire state, regardless
380- // of navigationId. This requires a breaking change to update the type on
381- // NavigationStart’s restoredState, which currently requires navigationId
382- // to always be present. The Router used to only restore history state if
383- // a navigationId was present.
384-
385- // The stored navigationId is used by the RouterScroller to retrieve the scroll
386- // position for the page.
387- const restoredState = event . state ?. navigationId ? event . state : null ;
388-
389- // Separate to NavigationStart.restoredState, we must also restore the state to
390- // history.state and generate a new navigationId, since it will be overwritten
391- if ( event . state ) {
392- const stateCopy = { ...event . state } as Partial < RestoredState > ;
393- delete stateCopy . navigationId ;
394- delete stateCopy . ɵrouterPageId ;
395- if ( Object . keys ( stateCopy ) . length !== 0 ) {
396- extras . state = stateCopy ;
397- }
398- }
399-
400- const urlTree = this . parseUrl ( event [ 'url' ] ! ) ;
401- this . scheduleNavigation ( urlTree , source , restoredState , extras ) ;
378+ this . navigateToSyncWithBrowser ( event [ 'url' ] ! , source , event . state ) ;
402379 } , 0 ) ;
403380 }
404381 } ) ;
405382 }
406383 }
407384
385+ /**
386+ * Schedules a router navigation to synchronize Router state with the browser state.
387+ *
388+ * This is done as a response to a popstate event and the initial navigation. These
389+ * two scenarios represent times when the browser URL/state has been updated and
390+ * the Router needs to respond to ensure its internal state matches.
391+ */
392+ private navigateToSyncWithBrowser (
393+ url : string , source : NavigationTrigger , state : RestoredState | undefined ) {
394+ const extras : NavigationExtras = { replaceUrl : true } ;
395+
396+ // TODO: restoredState should always include the entire state, regardless
397+ // of navigationId. This requires a breaking change to update the type on
398+ // NavigationStart’s restoredState, which currently requires navigationId
399+ // to always be present. The Router used to only restore history state if
400+ // a navigationId was present.
401+
402+ // The stored navigationId is used by the RouterScroller to retrieve the scroll
403+ // position for the page.
404+ const restoredState = state ?. navigationId ? state : null ;
405+
406+ // Separate to NavigationStart.restoredState, we must also restore the state to
407+ // history.state and generate a new navigationId, since it will be overwritten
408+ if ( state ) {
409+ const stateCopy = { ...state } as Partial < RestoredState > ;
410+ delete stateCopy . navigationId ;
411+ delete stateCopy . ɵrouterPageId ;
412+ if ( Object . keys ( stateCopy ) . length !== 0 ) {
413+ extras . state = stateCopy ;
414+ }
415+ }
416+
417+ const urlTree = this . parseUrl ( url ) ;
418+ this . scheduleNavigation ( urlTree , source , restoredState , extras ) ;
419+ }
420+
408421 /** The current URL. */
409422 get url ( ) : string {
410423 return this . serializeUrl ( this . currentUrlTree ) ;
@@ -562,7 +575,7 @@ export class Router {
562575 const urlTree = isUrlTree ( url ) ? url : this . parseUrl ( url ) ;
563576 const mergedTree = this . urlHandlingStrategy . merge ( urlTree , this . rawUrlTree ) ;
564577
565- return this . scheduleNavigation ( mergedTree , 'imperative' , null , extras ) ;
578+ return this . scheduleNavigation ( mergedTree , IMPERATIVE_NAVIGATION , null , extras ) ;
566579 }
567580
568581 /**
@@ -687,10 +700,6 @@ export class Router {
687700
688701 let targetPageId : number ;
689702 if ( this . canceledNavigationResolution === 'computed' ) {
690- const isInitialPage = this . currentPageId === 0 ;
691- if ( isInitialPage ) {
692- restoredState = this . location . getState ( ) as RestoredState | null ;
693- }
694703 // If the `ɵrouterPageId` exist in the state then `targetpageId` should have the value of
695704 // `ɵrouterPageId`. This is the case for something like a page refresh where we assign the
696705 // target id to the previously set value for that page.
0 commit comments