Routing
Basic syntax:
import { Routes } from '@angular/router';
const routes: Routes = [
{
path: 'my-component',
component: myComponent,
},
];
@NgModule({
// ...
imports: [
RouterModule.forRoot(routes),
// ...
]
})
<!-- angular built-in directive -->
<route-outlet></route-outlet>
Navigation
<a> link
The link can be added like: <a href="/my-component">
. But, Angular will rebuild the page when the user clicks on that, since Angular will send a request to the server. Not good :(.
It's better use:
-
<a routerLink="/my-component">
-
<a [routerLink]="['/my-component']">
Besides, using routerLinkActive
and routerLinkActiveOptions
can style the link.
router
import { Router } from '@angular/router';
export class oneComponent {
constructor(
private router: Router,
){}
someFn() {
this.router.navigate(['/my-component']);
}
}
For now, the route is absolute. We can use relative route, too.
import { Router, ActivatedRoute } from '@angular/router';
export class oneComponent {
constructor(
private router: Router,
private route: ActivatedRoute
){}
someFn() {
this.router.navigate(
['my-component'],
{ relativeTo: this.route }
);
}
}
route parameters
We can pass id
to the route:
const routes: Routes = [
{
path: 'my-component/:id',
component: myComponent,
},
];
To fetch id
, we can:
-
snapShot of route:
import { ActivatedRoute } from '@angular/router'; export class oneComponent { constructor( private route: ActivatedRoute ){} someFn() { const id = this.route.snapshot.params['id']; } }
The problem is, the route might be changed. We need read it asynchronically.
-
Observable of route:
this.route.params.subscribe( params => { const id = params['id']; } );
Query Parameters and Fragments can be used in router:
For example, url is prefix/my-component?userId=1#new
-
<a> link
:<a [routeLink]="['/my-component']" [queryParams]="{userId: '1'}" [fragment]="'new'" ></a>
-
router:
this.router.navigate( ['/my-component'], {queryParams: {userId: '1'}}, fragment: 'new' );
To get them:
-
snapShot of route:
const queryParams = this.route.snapshot.queryParams; const fragment = this.route.snapshot.fragment;
-
Observable of route:
this.route.queryParams.subscribe(); this.route.fragment.subscribe();
There an useful option:
-
queryParamsHandling:
preserve or override the queryParams of parent route.
this.router.navigate( ['my-component'], { relativeTo: this.route, queryParamsHandling: 'preserve' }),
wildcard and redirection
const routes: Routes = [
// all the other routes
{
path: '**', // match all the routes
redirectTo: '/not-found'
}
];
Here, it shows that the ordre in the array routes matters ! Angular reads the routes from top to bottom.
If the the path **
is placed at top, all the rest of the routes won't work.
Route Guards
A Guard can be added to check if a route can be accessed.
-
Create a Guard Service
@Injectable() export class AuthGuard implements CanActivate { constructor( private authService: AuthService, private router: Router) {} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean { if (somthing) { // logged in so return true return this.authService.isAuthenticated(); } else { this.router.navigate(['login ']); return this.authService.isNotAuthenticated(); } } }
-
Inject it into module
@NgModule({ // ... providers: [ AuthService, AuthGard ] }) export class AppModule {}
-
Use Guard in Routes
const routes: Routes = [ { path: 'my-component', component: MyComponent, canActivate: [AuthGuard], } ]
Besides,
canActivateChild
add Guard to the component and its children.canDeactivate
is a guard for leaving a route.
Static data in route
We can pass static data of route.
const routes: Routes = [
{
path: 'my-component',
component: MyComponent,
data: { message: 'some messages' }
}
]
const data = this.route.snapshot['data'];
// or
this.route.data.subscribe();
Dynamic data in route
We can create a Service which implements Resolver
to deal with dynamic data in route.
const routes: Routes = [
{
path: 'my-component',
component: MyComponent,
resolve: { myResolve: MyResolve }
}
]
this.route.data.subscribe(
data => {
this.data = data['myResolve'];
}
)
MyResolve
looks like:
@Injectable()
export class MyResolve implements Resolve<SomeType> {
constructor(
private someServer: SomeService
) {}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<SomeType> | Promise<SomeType> | SomeType {
return this.someService.getSomething();
}
}