Building detail pages – using route parameters

First, let's get back to the tasks list component template. We have a router that takes us to that list of tasks, but what if we wanted to a look at specific task, and what if we wanted that task on a specific page? We can easily solve that by doing the following:

  1. Update the tasks component to add a navigation capability per item that lets us navigate to a task detail view.
  2. Set up routing for one task, the URL path to it will be tasks/:id.
  3. Create a TaskDetail component that shows just one task.

Let's start with the first bullet point: updating tasks.component.ts.

It should be said that we can solve this in two ways:

  • Navigate imperatively
  • Build a route using routerLink that adds a parameter to the route

Let's try to show how to navigate imperatively first:

// app/tasks/tasks.component.html file

@Component({
selector: 'tasks',
template: `
<div*ngFor="let task of store | async">
{{ task.name }}
<button (click)="navigate(task)">Go to detail</button>
</div>

`
})
export class TasksComponent {
constructor(private router: Router) {}

navigate(task:Task) {
this.router.navigate(['/tasks',task.id]);
}
}

Let's highlight the following piece of code:

this.router.navigate(['/tasks',task.id]);

This produces a link that looks like /tasks/13 or /tasks/99. In this case, 13 and 99 are just made-up numbers to show what the route path might look like. 

The second way of navigating is to use the routerLink directive. To accomplish this, our preceding template will look slightly different:

<div*ngFor="let task of store | async">
{{ task.name }}
<a [routerLink]="['/tasks/',task.id]">Go to detail</a>
</div>

Both these ways work, just use the one that's best for you.

Now for the second item in the list, which is to set up routing, this will match the route path described previously. We open task/routes.ts and add the following entry to our list:

[
...
{
path : '/tasks/:id',
component : TaskDetailComponent
}
...
]

With this route in place, we have the last item in our list to fix, which is defining the TaskDetailComponent. Let's start with a simple version of it:

import { Component } from '@angular/core';

@Component({
selector: 'task-detail',
template: 'task detail'
})
export class TaskDetailComponent {
}

With all this in place, we are able to click a task in the list and navigate to a TaskDetailComponent. However, we are not satisfied here. The real reason for doing this was so we can do a more detailed lookup of a task. So, we are missing a data call from the TaskDetail component to our TaskService, where we ask for just one task. Remember how our route to TaskDetail was /tasks/:id? For us to make a correct call to our TaskService, we need to dig out the ID parameter from the route and use that as a parameter when calling our TaskService. If we route to /tasks/13, we need to call TaskService with a getTask(13) and expect one Task back.

So, we have two things to do:

  1. Dig out the router parameter ID from the route.
  2. Add a getTask(taskId) method to TaskService.

To succeed with the first mission, we can inject something called ActivatedRoute and talk to its params property, which is an Observable. The data coming from that Observable is an object where one of the properties is our route parameter:

this.route
.params
.subscribe( params => {
let id = params['id'];

});

Okay, so this only solves half the problem. We are able to dig out the value of our ID parameter this way, but we don't do anything with it. We should be performing a data fetch as well.

If we add a switchMap statement, then we can get hold of the data, carry out a data call, and return the result of the data instead, like so:

@Component({
template: `
<div *ngIf="(task$ | async) as task">
{{ task.name }}
</div>
`
})
export class TaskDetailComponent implements OnInit {
task$:Observable<Task>;

constructor(private route:ActivatedRoute) {}

ngOnInit() {
this.task$ = this.route
.params
.switchMap( params =>
this.taskService.getTask(+params['id'])
)
}
}

The last step is to add the getTask method to the TaskService:

export class TaskService{
...
getTask(id): Observable<Task> {
return this.http.get(`/tasks/${id}`).map(mapTask);
}
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset