27 June 2019
Angular (14) -- Routing
by Jerry Zhang
Day 22: Angular Routing
Passing Static Data to a Route
Previously, we created a page-not-found component and use the star star routing for the 404 errors. What about other
errors? Next, we will create a common error component called error-page
.
ng g c error-page --skipTests
In the template, we want to display some error message via string Interpolation.
<h4>{{ errorMessage }}</h4>
We add a property in this component.
errorMessage: string;
The problem is, what is the message?
- First, we link our
not-found
path to the new componentErrorPageComponent
. We pass a static data with the data property.
// { path: 'not-found', component: PageNotFoundComponent },
{ path: 'not-found', component: ErrorPageComponent, data: {message: 'Page not found!'} },
- Inject the
ActivatedRoute
and get the data.
ngOnInit() {
// this.errorMessage = this.route.snapshot.data['message'];
this.route.data.subscribe(
(data: Data) => {
this.errorMessage = data['message'];
}
);
}
Resolving Dynamic Data with the resolve Guard
Now let’s take a look at how to fetch some dynamic data before a route is displayed. For example, we need to fetch some data from the backend when we click a single item.
If we have such a use case, we need a Resolver
service, which will allow us to run some code before a route is
rendered. The difference to CanActivate
is the Resolver
will not decide whether this route should be rendered or
not and whether the component should be loaded or not. The Resolver
will always render the component in the end,
but it will do some pre-loading. It will fetch some data the component will then need later on.
-
Create a new file in the
server
component calledserver-resolver.service.ts
. -
In this class, we implement
Resolver
interface Server {
id: number;
name: string;
status: string;
}
@Injectable()
export class ServerResolver implements Resolve<Server> {
constructor(private serversService: ServersService) {}
resolve(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot):
Observable<Server> | Promise<Server> | Server {
return this.serversService.getServer(+route.params['id']);
}
}
Here, we outsource the getServer method. This code will be executed each time when we render a route.
-
Add this
ServerResolver
service as a provider in app.module.ts. -
Add it to our routing module. For example, we want to use it in our
ServerComponent
. Add aresolve
property.
{ path: ':id', component: ServerComponent, resolve: {server: ServerResolver} },
This will map the data that this resolver give us back, which it got from the resolve method, because this method
will be called whenever this route is loaded. So, the data will be stored in this server
object.
- Binding a property with the
data
Observable
ngOnInit() {
this.route.data
.subscribe(
(data: Data) => {
this.server = data['server'];
}
);
// const id = +this.route.snapshot.params['id'];
// this.server = this.serversService.getServer(id);
// this.route.params
// .subscribe(
// (params: Params) => {
// this.server = this.serversService.getServer(+params['id']);
// }
// );
}
Notice that data['server']
. This server
here has to match the name in the routing file that we assigned to the
resolve property.
This fetching data approach is very important when using asynchronous data.
Hash Mode Routing
Temporarily, we can use hash routing to make this application work on a real server. Later on, we will use a better way.
@NgModule({
imports: [
// RouterModule.forRoot(appRoutes, {useHash: true})
RouterModule.forRoot(appRoutes)
],
exports: [RouterModule]
})