Angular2 Routing: Basics

Angular2 Routing: Basics

What I'm covering in this post:

The source code covered in this post is available here

A lot of the content of this post can be found in the Angular2 docs as well.


Pre-requisites

I'm using Angular Cli to build and run the application. So to follow through the steps below, make sure you install the Angular Cli and all its pre-requisites. You can check their GitHub for more information.

Implementing Routing

Step 1 - First I'll create a Home component:

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

@Component({
    template: `<h1>Welcome Home!</h1>`
})
export class HomeComponent {
    constructor() {
    }
}

Step 2 - Now I go to my app.module to import and declare my Home component.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Step 3 - Now let's wire this up creating the app.routes.ts file.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';

const routes: Routes = [
    { path: '', component: HomeComponent }
];

export const routedComponents = RouterModule.forRoot(routes);

Step 4 - We need now to import the RouterModule to our app.module.

...
import { routedComponents } from './app.routes'

@NgModule({
  declarations: [...],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    routedComponents
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Step 5 - We're nearly there. One last thing though, in order to load the HomeComponent we have to update the app.component and add the router-outlet so it knows where to load the content of the HomeComponent:

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

@Component({
  template: `<router-outlet></router-outlet>`
})
export class AppComponent {
}

And there you go. Your routing is ready.

Switching Between Routes

Okay, so now that the routing is implemented, how can I switching between routes? Quite simple really, but first follow the steps 1 to 3 from previous section to create a new component called AdminComponent. At the end, our new app.routes should like this:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AdminComponent } from './admin/admin.component';

const routes: Routes = [
    { path: '', component: HomeComponent },
    { path: 'admin', component: AdminComponent }
];

export const routedComponents = RouterModule.forRoot(routes);

We now have a default route and also an admin route. We're ready to add some links to the app.component to navigate between routes, but first let's change slightly the app.component.ts as the html will start getting a bit bigger and move the template to a separate file.

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

@Component({
  templateUrl: './app.component.html'
})
export class AppComponent {
}

We now let's add our so expected links to the new app.component.html file

<div class="app-nav">
	<a md-button routerLink="/">Home</a>
	<a md-button routerLink="admin">Admin</a>
</div>
<div class="app-content">
	<router-outlet></router-outlet>
</div>

Done! The routerLink="/" will redirect to the root path and routerLink="admin" to the admin path.

Child Routes

Alright, child routes are actually pretty simple, all we need is adding a children property to one of the routes and specify the child routes the same way we specify the parent ones. Something like this:

const routes: Routes = [
    { path: '', component: HomeComponent },
    {
        path: 'admin', children: [
            { path: '', component: AdminComponent },
            { path: 'users', component: UsersComponent },
        ]
    }
];

So in this case, for us to access the UsersComponent we have to go the route /admin/users, if we just go to /admin we're going to land on the AdminComponent

Nested Outlets

In a lot of scenarios we will want to have some sort of template for a specific route. The same way we have the whole template around the main router-outlet, we might want to have some common ui controls for the admin area, navigation or filters of some sort. That's where you can start nesting the outlets
Nested Outlets

In the routes described in the Child Routes we have two children for admin: path:'' and path:'users', both of them will load in the main router-outlet specified in the app.component, but instead of loading this way, what I want to do is load the users.component inside admin.component inside app.component.

To achieve that I'll update my app.routes to look like this:

const routes: Routes = [
    { path: '', component: HomeComponent },
    {
        path: 'admin', component: AdminComponent, children: [
            { path: '' },
            { path: 'users', component: UsersComponent },
        ]
    }
];

I basically moved the component property from the first child of the admin route to the admin route itself. And after that what I have to do is update the admin.component template to include a router-outlet.

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

@Component({
  template: `
     <div>some common stuff used for all child routes</div>
     <router-outlet></router-outlet>
  `
})
export class AdminComponent {  
}

Auxiliary/Named Outlets

Now, this requires a bit more configurations and we need to keep in mind where the router-outlet is located especially when working with child routes. For now, let's keep it simple. Let's update the app.routes and include a new route called share:

const routes: Routes = [  
    { path: '', component: HomeComponent },
    { path: 'share', component: ShareComponent, outlet: 'bottom' },
    ...
];

You'll notice that a new property was introduced in this route outlet and this will tell the routing where this route needs to be loaded into. Now we have to update the app.component.html to include a new router-outlet.

<div class="app-nav">  
    <a md-button routerLink="/">Home</a>
    <a md-button routerLink="admin">Admin</a>
</div>  
<div class="app-content">  
    <router-outlet></router-outlet>
    <router-outlet name="bottom"></router-outlet>
</div>

So now if I try to access the share route, this will be loaded inside the bottom outlet instead of the nameless one. Cool! But how do I access the share route? Can I just go to /share? Not really. The way navigation works for named outlets is a bit unconventional, it will look like this /(bottom:share). This will basically load the root route with the home.component but also will load the share.component inside the bottom outlet.

And how do I add a link to my html so I can access this route? Again a bit unconventional:

<a [routerLink]="['/',{ outlets: { 'bottom': ['share'] } }]">Share</a>

Here you go. These are the basics. Happy routing.