The Angular 2 router is strictly connected to the component. It’s also called the Component Router (which is about to come to Angular 1.x as well). The main purpose of it is to have routable components. They are often smart components that are fetching resources from the API.
Let’s start with adding a router to the app. The very beginning is to add the general URL to that app which is accessible. This usually ends up with /
as the entrance point, but you may need to change it such as when you are trying to connect Angular 2 with an existing app.
The entire application is openly available at https://github.com/flauc/angular2-edge-app.
The base href is achieved by adding the element base
(in index.html
):
<base
href=
"/"
>
This is the only step you have to make in HTML. Next it’s time to configure providers. We move to the place where the app is being bootstrapped and import ROUTER_PROVIDERS
:
import
{
bootstrap
}
from
'@angular/platform-browser-dynamic'
;
import
{
ROUTER_PROVIDERS
}
from
'@angular/router'
;
import
{
AppComponent
}
from
'./app.component'
;
bootstrap
(
AppComponent
,
[
ROUTER_PROVIDERS
]);
This way we are able to inject router providers anywhere in the app and they will be singletons.
Now it’s time to add the first routable component. First of all, let’s recap the most basic component that App
could be:
import
{
Component
}
from
'@angular/core'
;
@
Component
({
selector
:
'app'
,
template
:
'Hello App'
})
class
AppComponent
{};
To add some routes we can start with their definitions:
import
{
Component
}
from
'@angular/core'
;
import
{
Routes
}
from
'@angular/router'
;
import
{
LoginComponent
}
from
'./pages/login/login.component'
;
import
{
SignupComponent
}
from
'./pages/signup/signup.component'
;
import
{
DashboardComponent
}
from
'./pages/dashboard/dashboard.component'
;
import
{
UserStoreService
}
from
'./common/services/userStore.service'
;
import
{
HomeComponent
}
from
'./pages/home/home.component'
;
@
Component
({
selector
:
'app'
,
template
:
'Hello App'
})
@
Routes
([
{
path
:
'/'
,
component
:HomeComponent
},
{
path
:
'/login'
,
component
:LoginComponent
},
{
path
:
'/signup'
,
component
:SignupComponent
},
{
path
:
'/dashboard'
,
component
:DashboardComponent
},
// Catch route
{
path
:
'*'
,
component
:HomeComponent
}
])
class
AppComponent
{};
Now we do have configuration for this particular component, but routes won’t be visible. It’s happening because of the lack of a place where the router should render its content. So we’re importing ROUTER_DIRECTIVES
:
import
{
ROUTER_DIRECTIVES
,
Routes
}
from
'@angular/router'
;
...
@
Component
({
selector
:
'app'
,
directives
:ROUTER_DIRECTIVES
,
template
:
`
<
router
-
outlet
><
/router-outlet>
`
})
...
This time, instead of a simple string, we’re using RouterOutlet
to make a placeholder for routable components. If you change the URL to match some path it should render the proper component.
It works perfectly but lacks a very important feature - links to other routes. This one is achieved by the RouterLink
directive. With the appropriate parameters it can route to named routes. Look at the template:
import
{
Component
}
from
'@angular/core'
;
import
{
ROUTER_DIRECTIVES
,
Routes
}
from
'@angular/router'
;
import
{
LoginComponent
}
from
'./pages/login/login.component'
;
import
{
SignupComponent
}
from
'./pages/signup/signup.component'
;
import
{
DashboardComponent
}
from
'./pages/dashboard/dashboard.component'
;
import
{
UserStoreService
}
from
'./common/services/userStore.service'
;
import
{
HomeComponent
}
from
'./pages/home/home.component'
;
@
Component
({
selector
:
'app'
,
directives
:ROUTER_DIRECTIVES
,
template
:
`
<
nav
>
<
ul
>
<
li
><
a
[
routerLink
]
=
"['/home']"
>
Home
<
/a></li>
<
li
><
a
[
routerLink
]
=
"['/dashboard']"
>
Dashboard
<
/a></li>
<
li
><
a
[
routerLink
]
=
"['/login']"
>
Log
In
<
/a></li>
<
li
><
a
[
routerLink
]
=
"['/signup']"
>
Sign
Up
<
/a></li>
<
/ul>
<
/nav>
<
router
-
outlet
><
/router-outlet>
`
})
@
Routes
([
{
path
:
'/'
,
component
:HomeComponent
},
{
path
:
'/login'
,
component
:LoginComponent
},
{
path
:
'/signup'
,
component
:SignupComponent
},
{
path
:
'/dashboard'
,
component
:DashboardComponent
},
// Catch route
{
path
:
'*'
,
component
:HomeComponent
}
])
class
AppComponent
{};
The configuration and code up to this point should give a working rout to the proper components basing on the routing table provided for the component.
We’re able to route to the static URL path, but now it’s time to make it more dynamic. The first thing you meet when trying to solve real problems is to add a dynamic id to the URL. It’s quite easy in Angular 2. Let’s consider following the dashboard component:
@
Component
({
selector
:
'dashboard'
,
template
:
`
<
router
-
outlet
><
/router-outlet>
<
a
[
routerLink
]
=
"['./', 'room1']"
>
Go
to
room1
<
/a>
`
.
directives
:ROUTER_DIRECTIVES
})
@
Routes
([
{
path
:
'/'
,
component
:DashboardMainComponent
},
{
path
:
'/:name'
,
component
:RoomComponent
},
// Catch All route
{
path
:
'*'
,
component
:DashboardMainComponent
}
])
In the routes you’ll see:
{
path
:
'/:name'
,
component
:RoomComponent
},
It indicates a path with a parameter. This path can be supplied either by entering with the proper URL, or by adding a router link with a second parameter in the array:
<
a
[
routerLink
]
=
"['./', 'room1']"
>
Go
to
room1
<
/a>
The router link gets a DSL path as the first item in the array. It can be either absolute or relative. The second one is part of the URL. In our case it passes the name to the component, which is accessible by /:name
. The first is the map of query string parameters.
On the other hand, in the component we just routed to it would be nice to get the params there. Like Angular component hooks, the router adds its own. Angular fires the onInit
hook when it initializes the component. In the same way we can implement router interfaces inside the class that has the @Routes
annotation. We are able to use following hooks:
OnActivate
- fired upon a successfully activated routeCanDeactivate
- defines whether a component can be deactivatedThe one that is especially useful here is OnActivate
. It let’s you define code that has to be invoked right after successful redirection. Moreover, it gives us information about current and previous routes. We’ll incorporate that in the following manner:
import
{
OnActivate
,
Router
,
RouteSegment
,
RouteTree
}
from
'@angular/router'
;
...
class
RoomComponent
implements
OnActivate
{
private
selectedName
:number
;
routerOnActivate
(
curr
:RouteSegment
,
prev?
:RouteSegment
,
currTree?
:RouteTree
,
prevTree?
:RouteTree
)
:
void
{
this
.
selectedName
=
curr
.
getParam
(
'name'
);
}
}
Now we were able to get the param passed by the URL directly to the code.