Building a new component for demonstration purposes
So far, we have built two well-differentiated components we can leverage to deliver a multipage navigation. But in order to provide a better user experience, we might need a third one.
We will create a component in our tasks
feature folder, anticipating the form we will use in the next chapter to publish new tasks. Create the following files in the locations pointed out for each one:
app/tasks/task-editor.component.ts
import { Component } from 'angular2/core'; import { ROUTER_DIRECTIVES } from 'angular2/router'; @Component({ selector: 'pomodoro-tasks-editor', directives: [ROUTER_DIRECTIVES], templateUrl: 'app/tasks/task-editor.component.html' }) export default class TaskEditorComponent { constructor() {} }
app/tasks/task-editor.component.html
<form class="container"> <h3>Task Editor:</h3> <div class="form-group"> <input type="text" class="form-control" placeholder="Task name" required> </div> <div class="form-group"> <input type="Date" class="form-control" required> </div> <div class="form-group"> <input type="number" class="form-control" placeholder="Pomodoros required" min="1" max="4" required> </div> <div class="form-group"> <input type="checkbox" name="queued"> <label for="queued"> this task by default?</label> </div> <p> <input type="submit" class="btn btn-success" value="Save"> <a href="/" class="btn btn-danger">Cancel</a> </p> </form>
This is the most basic definition of a component, but we will also bring the ROUTER_DIRECTIVES
symbol from the router library. This will provide us support, as we will see later on, to include routing directives in our HTML template. This will be used to introduce links in our template to jump to other components, as we will see shortly. Last but not least, we need to expose this new component from our feature folder facade:
app/tasks/tasks.ts
import TasksComponent from './tasks.component'; import TaskEditorComponent from './task-editor.component'; import TaskTooltipDirective from './task-tooltip.directive'; const TASKS_DIRECTIVES: any[] = [ TasksComponent, TaskEditorComponent, TaskTooltipDirective ]; export { TASKS_DIRECTIVES, TasksComponent, TaskEditorComponent, TaskTooltipDirective };
Configuring the RouteConfig decorator with the RouteDefinition instances
In order to achieve these goals, we need to start building our top router, which will be in charge of kicking off the routes’ scaffolding. The logical path begins in our top root component. Open its file module and import the following tokens, right next to the ROUTER_PROVIDERS
symbol we imported at the beginning of this chapter. The code is as follows:
app/app.component.ts
... import { ROUTER_PROVIDERS, RouteConfig, ROUTER_DIRECTIVES } from '@angular/router-deprecated'; import { TimerComponent } from './timer/timer'; import { TasksComponent, TaskEditorComponent } from './tasks/tasks'; ...
The RouteConfig
represents the decorator type that will turn our component into a router component. The ROUTER_DIRECTIVES
symbol wraps the view directives we will need shortly to link to these routes. We also import the tokens of all the three components we will be dealing with. As we will shortly see, each route needs to declare the type of the component we are routing the browser to.
Let’s continue by replacing the directives in our AppComponent
module by the ROUTE_DIRECTIVES
symbol, since we will not need to declare the facade tokens of the components that lived in its template anymore. The router will handle this for us:
app/app.component.ts
@Component({ selector: 'pomodoro-app', directives: [ROUTER_DIRECTIVES], providers: [SHARED_PROVIDERS, HTTP_PROVIDERS, ROUTER_PROVIDERS], template: ` ... })
Now, let’s expand the component
class definition with the RouteConfig
decorator by appending the following decorator right after the @Component
decorator block and before the class statement:
app/app.component.ts
@RouteConfig([ { path: '', name: 'TasksComponent', component: TasksComponent }, { path: 'tasks/editor', name: 'TaskEditorComponent', component: TaskEditorComponent }, { path: 'timer', name: 'TimerComponent', component: TimerComponent } ]) export default class AppComponent {}
As we pointed out at the beginning of this chapter, the RouteConfig
decorator must be populated with an array of RouteDefinition
objects, each one specifying a path that, once reached by the user, will enable the component whose type we have defined in the component property.
Tip
Note: The new Router replaced the @RouteConfig
decorator by the @Routes
decorator. The name property is removed from the route definitions schema and route matching is performed just by checking the path value.
In the previous example, our host component will react to three different routes and thus serve the TasksComponent
item, the TimerComponent
item, or the TaskEditorComponent
item depending on the route’s path.
Tip
Here we stumble upon another common convention in the previous version fo the Angular 2 router: naming routes with the same name as the component they refer to. As we will see shortly, we will use each route name for populating the links pointing to each resource, so naming routes after the component they will activate becomes pretty useful and intuitive when it comes to assessing the target of each link found in the template. This convention is no longer enforced in the new router, since only paths are used to perform route matching.
There are two questions at this point: where will these components be rendered and how will we trigger each route? In order to answer these questions, we need to look into the router directives in detail.