Navigating around a single page application is a fundamental task, and Angular offers you a built-in directive, routerLink
, to accomplish this.
The code, links, and a live example of this are available at .
Begin with the application setup assembled in the Setting up an application to support simple routes recipe.
Your goal is to add an additional route to this application accompanied by a component; also, you want to be able to navigate between them using links.
To begin, create another component, ArticleComponent
, and an associated route:
[app/article/article.component.ts] import {Component} from '@angular/core'; @Component({ template: 'Article component!' }) export class ArticleComponent {}
Next, install an article route accompanied by this new component:
[app/app.module.ts] import {NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {RouterModule, Routes} from '@angular/router'; import {RootComponent} from './root.component'; import {DefaultComponent} from './default.component'; import {ArticleComponent} from './article.component'; const appRoutes:Routes = [ {path: 'article', component: ArticleComponent}, {path: '**', component: DefaultComponent} ]; @NgModule({ imports: [ BrowserModule, RouterModule.forRoot(appRoutes) ], declarations: [ DefaultComponent, ArticleComponent, RootComponent ], bootstrap: [ RootComponent ] }) export class AppModule {}
With the routes defined, you can now build a rudimentary navbar comprised of routerLinks
. The markup surrounding the <router-outlet>
tag will remain irrespective of the route, so the root app component seems like a suitable place for the nav links.
The routerLink
directive is available as part of RouterModule
, so you can go straight to adding some anchor tags:
[app/root.component.ts] import {Component} from '@angular/core'; @Component({ selector: 'root', template: ` <h1>Root component</h1> <a [routerLink]="''">Default</a> <a [routerLink]="'article'">Article</a> <router-outlet></router-outlet> ` }) export class RootComponent {}
In this case, since the routes are simple and static, binding routerLink
to a string is allowed. routerLink
also accepts the array notation:
[app/root.component.ts] import {Component} from '@angular/core'; @Component({ selector: 'root', template: ` <h1>Root component</h1> <a [routerLink]="['']">Default</a> <a [routerLink]="['article']">Article</a> <router-outlet></router-outlet> ` }) export class RootComponent {}
For the purpose of this recipe, the array notation doesn't add anything. However, when developing more complicated URL structures, the array notation becomes useful, as it allows you to generate links in a piecewise fashion.
At a high level, this is no different than the behavior of a vanilla href
attribute. After all, the routes behave in the same way and are structured similarly. The important difference here is that using a routerLink
directive instead of href
allows you to move around your application the Angular way, without ever having the anchor tag click interpreted by the browser as a non-Angular navigation event.
Of course, the routerLink
directive is also superior as it is more extensible as a tool for navigating. Since it is an HTML attribute after all, there's no reason routerLink
can't be attached to, for example, a button instead:
[app/root.component.ts] import {Component} from '@angular/core'; @Component({ selector: 'root', template: ` <h1>Root component</h1> <button [routerLink]="['']">Default</button> <button [routerLink]="['article']">Article</button> <router-outlet></router-outlet> ` }) export class RootComponent {}
What's more, you'll also note that the array notation allows the dynamic generation of links via all of the tremendous data binding that Angular affords you:
[app/root.component.ts] import {Component} from '@angular/core'; @Component({ selector: 'root', template: ` <h1>Root component</h1> <a [routerLink]="[defaultPath]">Default</a> <a [routerLink]="[articlePath]">Article</a> <router-outlet></router-outlet> ` }) export class RootComponent { defaultPath:string = ''; articlePath:string = 'article'; }
As the URL structure gets ever more advanced, it will be easy to see how a clever application of data binding could make for some very elegant dynamic link generation.
The ordering of routes inside the Routes
definition specifies the descending priority of each of them. In this recipe's example, suppose you were to reverse the order of the routes:
[app/app.module.ts] import {NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {RouterModule, Routes} from '@angular/router'; import {RootComponent} from './root.component'; import {DefaultComponent} from './default.component'; import {ArticleComponent} from './article.component'; const appRoutes:Routes = [ {path: '**', component: DefaultComponent}, {path: 'article', component: ArticleComponent} ]; @NgModule({ imports: [ BrowserModule, RouterModule.forRoot(appRoutes) ], declarations: [ DefaultComponent, ArticleComponent, RootComponent ], bootstrap: [ RootComponent ] }) export class AppModule {}
When experimenting, you will find that the browser's URL changes correctly with the various routerLink
interactions, but both routes will use DefaultComponent
as the rendered view. This is simply because all the routes match the **
catchall, and Angular doesn't bother to traverse the routes any further once it has a matching route. Keep this in mind when authoring large route tables.