UI-Router issues after migrating to Angular Router

Loading

When migrating an application from AngularJS (1.x) to Angular (2+), one of the biggest challenges is transitioning from UI-Router (@uirouter/angularjs) to Angular Router (@angular/router).

Since UI-Router and Angular Router work differently, developers often face issues like:

  • Broken routes after migration
  • State parameters not passing correctly
  • Lazy loading issues
  • Navigation problems due to different lifecycle hooks

This guide explains common UI-Router issues after migration and provides step-by-step solutions for each.


1. Key Differences Between UI-Router and Angular Router

FeatureUI-Router (@uirouter/angularjs)Angular Router (@angular/router)
State-Based NavigationUses states ($stateProvider) instead of routesUses route-based navigation (RouterModule)
Nested ViewsSupports multiple views per stateUses child routes with <router-outlet>
URL ParametersUses :param or params objectUses :param and queryParams
Lazy LoadingSupports manual state lazy loadingUses loadChildren
Navigation Methods$state.go('stateName')router.navigate(['path'])

2. Common Issues and Fixes

Issue #1: Routes Not Working After Migration

Problem

  • After switching from UI-Router to Angular Router, some routes do not work, showing a blank page or 404 Not Found.

Cause

  • UI-Router follows state-based navigation ($stateProvider), while Angular Router uses path-based navigation (RouterModule).
  • Old states may not match Angular Router’s path structure.

Solution: Convert UI-Router States to Angular Routes

Old UI-Router State

$stateProvider.state('home', {
url: '/home',
templateUrl: 'home.html',
controller: 'HomeController'
});

New Angular Route

const routes: Routes = [
{ path: 'home', component: HomeComponent }
];
  • Add routes to AppModule:
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}

Issue #2: URL Parameters Not Passing Correctly

Problem

  • UI-Router allows passing parameters as objects, but Angular Router requires them in the URL or queryParams.
  • Example: $state.go('product', { id: 123 }) works in UI-Router, but router.navigate(['/product'], { queryParams: { id: 123 } }) is required in Angular.

Solution: Update Navigation and Route Definitions

Old UI-Router

$stateProvider.state('product', {
url: '/product/:id',
templateUrl: 'product.html',
controller: 'ProductController'
});
jsCopyEdit$state.go('product', { id: 123 });

New Angular Router

const routes: Routes = [
{ path: 'product/:id', component: ProductComponent }
];
this.router.navigate(['/product', 123]);

Fetching Route Parameters in Angular

constructor(private route: ActivatedRoute) {}

ngOnInit() {
this.route.params.subscribe(params => {
console.log('Product ID:', params['id']);
});
}

Issue #3: Nested Views Not Rendering

Problem

  • UI-Router supports multiple views using views inside a state.
  • Angular Router only supports one primary router outlet.

Solution: Use Child Routes in Angular Router

Old UI-Router Nested State

$stateProvider.state('dashboard', {
url: '/dashboard',
views: {
'sidebar': { templateUrl: 'sidebar.html' },
'content': { templateUrl: 'dashboard.html' }
}
});

New Angular Router with Child Routes

const routes: Routes = [
{
path: 'dashboard', component: DashboardComponent,
children: [
{ path: 'sidebar', component: SidebarComponent },
{ path: 'content', component: DashboardContentComponent }
]
}
];

Updated HTML

<router-outlet></router-outlet>
<router-outlet name="sidebar"></router-outlet>

Issue #4: Lazy Loading Not Working

Problem

  • UI-Router uses lazyLoad inside state definitions, while Angular Router uses loadChildren.

Solution: Convert UI-Router Lazy Loading to Angular

Old UI-Router Lazy Loading

$stateProvider.state('lazy', {
url: '/lazy',
lazyLoad: function(transition) {
return import('./lazy.module').then(mod => {
return mod.LazyModule;
});
}
});

New Angular Lazy Loading

const routes: Routes = [
{ path: 'lazy', loadChildren: () => import('./lazy.module').then(m => m.LazyModule) }
];

Ensure LazyModule has its own RouterModule:

@NgModule({
imports: [RouterModule.forChild([{ path: '', component: LazyComponent }])],
exports: [RouterModule]
})
export class LazyModule {}

Issue #5: $state.go() Not Working

Problem

  • $state.go() from UI-Router no longer works after migrating to Angular.

Solution: Replace $state.go() with router.navigate()

Old UI-Router

$scope.goToDashboard = function() {
$state.go('dashboard');
};

New Angular Router

constructor(private router: Router) {}

goToDashboard() {
this.router.navigate(['/dashboard']);
}

Issue #6: UI-Router $transition$ Hooks Not Triggering

Problem

  • UI-Router allows transition hooks like:
$transitions.onStart({ to: '*' }, function(transition) {
console.log('Navigation started:', transition.to().name);
});
  • Angular Router does not support hooks like UI-Router.

Solution: Use Angular Router Events

import { Router, NavigationStart } from '@angular/router';

constructor(private router: Router) {}

ngOnInit() {
this.router.events.subscribe(event => {
if (event instanceof NavigationStart) {
console.log('Navigation started:', event.url);
}
});
}

Best Practices for Migration

Convert UI-Router states to Angular Router routes one at a time.
Use Angular’s ActivatedRoute instead of $stateParams.
Ensure nested views are properly converted into child routes.
Use loadChildren instead of lazyLoad.
Replace $state.go() with router.navigate().
Monitor navigation events using Router events.

Leave a Reply

Your email address will not be published. Required fields are marked *