Routing
AngularDart uses the angulardart_router package for client-side routing.
Setup
Add the router dependency:
dependencies:
angulardart: '>=9.0.0 <10.0.0'
angulardart_router: '>=5.0.0 <6.0.0'
Basic Configuration
import 'package:angulardart/angular.dart';
import 'package:angulardart_router/angulardart_router.dart';
@Component(
selector: 'app-component',
template: '<nav>'
'<a [routerLink]="[\'/\']">Home</a>'
'<a [routerLink]="[\'/about\']">About</a>'
'<a [routerLink]="[\'/users\']">Users</a>'
'</nav>'
'<router-outlet [routes]="routes"></router-outlet>',
directives: [routerDirectives],
)
class AppComponent implements OnInit {
final Router _router;
List<RouteDefinition> routes = [];
AppComponent(this._router);
@override
void ngOnInit() {
routes = [
RouteDefinition(
path: '/',
component: HomeComponentFactory,
useAsDefault: true,
),
RouteDefinition(
path: '/about',
component: AboutComponentFactory,
),
RouteDefinition(
path: '/users',
component: UsersComponentFactory,
),
];
}
}
Route Parameters
Define routes with parameters using :paramName:
routes = [
RouteDefinition(path: '/users/:id', component: UserDetailComponentFactory),
];
Access parameters in components:
@Component(
selector: 'user-detail',
template: '<h1>{{ userId }}</h1>',
)
class UserDetailComponent implements OnInit {
final Router _router;
String? userId;
UserDetailComponent(this._router);
@override
void ngOnInit() {
final path = _router.current?.path ?? '';
final segments = path.split('/');
userId = segments.isNotEmpty ? segments.last : null;
}
}
Query Parameters
Navigate with query parameters:
_router.navigate('/search', NavigationParams(
queryParameters: {'q': 'dart', 'page': '1'},
));
Access query parameters:
final query = _router.current?.queryParameters['q'];
Route Guards
CanActivate
Protect routes from unauthorized access:
class AuthGuard implements CanActivate {
final AuthService _authService;
AuthGuard(this._authService);
@override
Future<bool> canActivate(
RouterState? current,
RouterState next,
) async {
return _authService.isLoggedIn;
}
}
// Usage in routes
routes = [
RouteDefinition(
path: '/admin',
component: AdminComponentFactory,
canActivate: [AuthGuard],
),
];
CanDeactivate
Prevent navigation away from unsaved changes:
class UnsavedChangesGuard implements CanDeactivate {
@override
Future<bool> canDeactivate(
RouterState current,
RouterState? next,
) async {
// Show confirmation dialog
return window.confirm('You have unsaved changes. Leave anyway?');
}
}
Child Routes
Define nested routes:
routes = [
RouteDefinition(
path: '/dashboard',
component: DashboardComponentFactory,
children: [
RouteDefinition(
path: 'overview',
component: OverviewComponentFactory,
),
RouteDefinition(
path: 'analytics',
component: AnalyticsComponentFactory,
),
],
),
];
Dashboard template with child outlet:
<div class="dashboard">
<nav>
<a [routerLink]="['/dashboard', 'overview']">Overview</a>
<a [routerLink]="['/dashboard', 'analytics']">Analytics</a>
</nav>
<router-outlet [routes]="childRoutes"></router-outlet>
</div>
Programmatic Navigation
@Component(
selector: 'login-form',
template: '<form (ngSubmit)="login()">'
'<input [(ngModel)]="email" name="email">'
'<button type="submit">Login</button>'
'</form>',
directives: [formDirectives],
)
class LoginFormComponent {
final Router _router;
String email = '';
LoginFormComponent(this._router);
void login() async {
// Perform login...
await _router.navigate('/dashboard');
}
}
Navigation Events
Listen to route changes:
@Component(
selector: 'app-component',
template: '<router-outlet></router-outlet>',
)
class AppComponent implements OnInit, OnDestroy {
final Router _router;
StreamSubscription? _sub;
AppComponent(this._router);
@override
void ngOnInit() {
_sub = _router.onRouteActivated.listen((state) {
print('Navigated to: ${state.path}');
// Scroll to top on navigation
window.scrollTo(0, 0);
});
}
@override
void ngOnDestroy() {
_sub?.cancel();
}
}
Wildcard Routes
Handle unknown routes:
routes = [
RouteDefinition(path: '/', component: HomeComponentFactory),
RouteDefinition(path: '/about', component: AboutComponentFactory),
RouteDefinition(
path: '/**',
component: NotFoundComponentFactory,
),
];
Lazy Loading
Load components on demand to reduce initial bundle size:
routes = [
RouteDefinition(
path: '/admin',
loader: () async {
// Dynamic import
await loadLibrary('package:my_app/admin_component.dart');
return adminComponentFactory;
},
),
];
Best Practices
- Use path-based routes over named routes
- Implement route guards for protected areas
- Handle 404 routes with a wildcard
- Use lazy loading for large feature modules
- Scroll to top on navigation
- Use query parameters for filterable content