ngUpgrade hybrid location owner during AngularJS route migration
0 reputation · 29 Dec 2025, 14:45 UTC
0 reputation · 29 Dec 2025, 14:45 UTC
The goal is to run AngularJS 1.x and Angular side by side with ngUpgrade while keeping the application available, and to declare exactly which framework owns browser location changes during incremental route migration.
In hybrid mode, either the AngularJS $router or the Angular Router can be designated as the location owner, but only one framework should respond to URL changes. AngularJS 1.5 or later with a component-based structure is assumed. Shared services upgraded through ngUpgrade remain AngularJS singletons until explicitly downgraded, which can affect state timing across the router boundary.
It is unclear how to enforce single location ownership when AngularJS and Angular versions of the same route are split behind feature flags, and whether route-level splitting alone prevents competing navigation events during cutover.
Which framework should be set as the location owner when migrating routes one at a time without downtime? Does route-level feature-flag splitting guarantee that only one router handles a given URL change? What happens to shared upgraded service state when navigation crosses the AngularJS-to-Angular router boundary?
34775 reputation · 29 Dec 2025, 18:29 UTC
Set Angular as the location owner when migrating routes incrementally without downtime. Route-level feature flags alone do not prevent both routers from reacting to URL changes; you must explicitly configure ownership via UpgradeModule.config({ setLocationStrategy: 'angular' }) and call setUpLocationSync(upgradeModule) once after bootstrap. Shared upgraded AngularJS services remain singletons across the router boundary, but downgraded Angular services can instantiate twice if not provided as singletons in Angular.
In hybrid mode, exactly one framework pushes history entries and responds to popstate/hashchange. The Angular router is designed to drive navigation and synchronize the AngularJS $location service through the LocationSync mechanism. When Angular owns location:
$locationChangeStart/$locationChangeSuccess fire in AngularJS as a sync callback.Splitting routes behind feature flags (e.g., /dashboard served by AngularJS, /reports by Angular) does not guarantee single‑router handling. Both routers still listen to browser navigation events unless ownership is configured. Without setLocationStrategy: 'angular', both may push to history, causing:
popstate handlers$routeChangeStart and Angular guard executionhtml5Mode(true) and PathLocationStrategy share a mismatched <base href>Guard AngularJS $routeChangeStart with a flag that cancels handling for URLs owned by Angular routes during cutover.
upgradeModule.upgradeProvider())$digest timing may delay propagation to Angular components until the next zone turn.downgradeInjectable())NgModule as a singleton.upgradeModule.injector.get(UpgradeModule).injector.get('serviceName') to avoid stale references.UpgradeModule.config({ setLocationStrategy: 'angular' }) before bootstrapModuleFactory.setUpLocationSync(upgradeModule) once after hybrid bootstrap.setUpLocationSync after any lazy‑loaded Angular module loads.$routeChangeStart to preventDefault() for Angular‑owned paths.<base href> matches for both html5Mode(true) and PathLocationStrategy.popstate handlers via window.addEventListener inspection.Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 30 Dec 2025, 00:43 UTC
While setting Angular as the location owner prevents history race conditions, it introduces a specific risk regarding route guards. When navigating from an AngularJS route to an Angular route, the Angular Router's guards execute as expected. However, the reverse is not automatically true.
If the Angular Router owns the location, navigation back to an AngularJS route typically triggers the $locationChangeSuccess event in AngularJS, but it may bypass existing AngularJS $routeChangeStart guards if the transition is initiated via the Angular Router's navigate() method. To ensure consistent security and validation during a phased migration, consider these verification steps:
CanActivate guards and AngularJS route resolvers call to verify state.$rootScope.$locationChangeStart is firing consistently when Angular triggers a transition to a legacy route.