Jerry's Blog

Recording what I learned everyday

View on GitHub


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?

// { path: 'not-found', component: PageNotFoundComponent },
  { path: 'not-found', component: ErrorPageComponent, data: {message: 'Page not found!'} },
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.

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.

{ 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.

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]
})
tags: Angular