1. Understanding Nested Routes in UI-Router
UI-Router allows nested views for better component-based structure in AngularJS. However, if not configured correctly, issues such as:
- Parent and child states not displaying properly
- Views overlapping or not rendering
- URL conflicts
- Controllers not loading
can arise.
2. Common Issues & Fixes
Fix 1: Ensure UI-Router (ui.router
) is Added to the Module
UI-Router must be included for state-based routing to work.
Incorrect (Routes Won’t Work)
var app = angular.module('myApp', []); // Missing 'ui.router'
Corrected Code
var app = angular.module('myApp', ['ui.router']); // Includes 'ui.router'
- Without
ui.router
, nested routes will not work.
Fix 2: Use Named Views Correctly
Named views are required for child states to be properly rendered inside ui-view
.
Incorrect (Causes View Overlaps or Missing UI)
$stateProvider
.state('dashboard', {
url: '/dashboard',
templateUrl: 'dashboard.html'
})
.state('dashboard.reports', {
url: '/reports',
templateUrl: 'reports.html' // Will not load inside dashboard
});
- Here,
reports.html
does not have a named view, so it won’t be injected properly.
Corrected Code (Using views
for Named UI Injection)
$stateProvider
.state('dashboard', {
url: '/dashboard',
templateUrl: 'dashboard.html'
})
.state('dashboard.reports', {
url: '/reports',
views: {
'content@dashboard': { // Use named view inside parent
templateUrl: 'reports.html'
}
}
});
- This ensures
reports.html
loads insidedashboard.html
instead of replacing the entire UI.
Fix 3: Add ui-view
Inside Parent Template
Ensure the parent template has <ui-view>
where the child state should render.
Incorrect (No Place for Child View)
<!-- dashboard.html -->
<h1>Dashboard</h1>
- Without
<ui-view>
, the child view has nowhere to be injected.
Corrected Code
<!-- dashboard.html -->
<h1>Dashboard</h1>
<div ui-view="content"></div> <!-- Named view for child states -->
- The child state (
dashboard.reports
) will now render inside thisui-view
.
Fix 4: Use Absolute Named Views to Avoid Conflicts
When using multiple named views, always specify absolute state names.
Incorrect (Causes View Conflicts)
$stateProvider
.state('main', {
url: '/main',
templateUrl: 'main.html'
})
.state('main.sidebar', {
url: '/sidebar',
views: {
'content': { // May cause conflicts
templateUrl: 'sidebar.html'
}
}
});
Corrected Code
$stateProvider
.state('main', {
url: '/main',
templateUrl: 'main.html'
})
.state('main.sidebar', {
url: '/sidebar',
views: {
'content@main': { // Absolute reference to parent
templateUrl: 'sidebar.html'
}
}
});
- Ensures the sidebar view loads inside
main.html
.
Fix 5: Avoid URL Conflicts Between Parent & Child States
If a parent and child state share the same URL segment, the child may not load properly.
Incorrect (URL Conflict)
$stateProvider
.state('profile', {
url: '/profile', // Same as child segment
templateUrl: 'profile.html'
})
.state('profile.settings', {
url: '/profile/settings', // Causes conflict
templateUrl: 'settings.html'
});
- The child state’s URL (
/profile/settings
) overlaps with the parent (/profile
), causing unexpected behavior.
Corrected Code
$stateProvider
.state('profile', {
url: '/profile',
templateUrl: 'profile.html'
})
.state('profile.settings', {
url: '/settings', // Relative URL inside parent
templateUrl: 'settings.html'
});
- Now, visiting
/profile/settings
properly loadssettings.html
insideprofile.html
.
Fix 6: Use abstract: true
for Parent States Without a View
If a parent state is only a container for child states, mark it as abstract.
Incorrect (Parent Has No View, Causing Errors)
$stateProvider
.state('admin', {
url: '/admin' // No template, but still navigable
})
.state('admin.users', {
url: '/users',
templateUrl: 'users.html'
});
Corrected Code
$stateProvider
.state('admin', {
abstract: true, // Prevents direct navigation
url: '/admin'
})
.state('admin.users', {
url: '/users',
templateUrl: 'users.html'
});
- Prevents the user from navigating to
/admin
directly without breaking child states.
Fix 7: Debug UI-Router with $stateChangeSuccess
If routes are still not working, log state changes.
app.run(function($rootScope) {
$rootScope.$on("$stateChangeSuccess", function(event, toState, toParams, fromState) {
console.log("Navigated to:", toState.name);
});
});
- Helps track which state is loading and diagnose issues.