Routing Basics 4.0

Send feedback

Milestone

Create a new project named router_example, and populate it as described in Setup for Development. Then add the router and forms packages as pubspec dependencies:

pubspec.yaml (dependencies)

dependencies: angular: ^4.0.0 angular_forms: ^1.0.0 angular_router: ^1.0.2

For this first milestone, you’ll create a rudimentary version of the app that navigates between two (placeholder) views.

App in action

Set the base href

The router uses the browser’s history.pushState for navigation. Thanks to pushState, you can make in-app URLs indistinguishable from server URLs, for example localhost:3000/crisis-center.

Modern HTML 5 browsers were the first to support pushState which is why many people refer to these URLs as “HTML 5 style” URLs.

HTML 5 style is the router default. See the Appendix on LocationStrategy and browser URL styles to learn why HTML 5 style is preferred, how to adjust its behavior, and how to switch to the older hash (#) style, when necessary.

You must add a <base href> element to the app’s index.html for pushState routing to work. The browser uses the base href value to prefix relative URLs when referencing CSS files, scripts, and images.

The starter app sets the <base> element dynamically, so that sample apps built from it can be run and tested during development using any of the officially recommended tools:

web/index.html (base-href)

<script> // WARNING: DO NOT set the <base href> like this in production! // Details: https://webdev.dartlang.org/angular/guide/router (function () { // App being served out of web folder (like WebStorm does)? var match = document.location.pathname.match(/^\/[-\w]+\/web\//); var href = match ? match[0] : '/'; document.write('<base href="' + href + '" />'); }()); </script>

For a production build, replace the <script> with a <base> element where the href is set to your application’s root path. If the path is empty, then use:

<head> <base href="/"> ... </head>

You can also statically set the <base href> during development. When running pub serve from the command line, use href="/". When running apps from WebStorm, use href="my_project/web/", where my_project is the name of your project.

<base href="/my_project/web/">

Configure the routes for the Router

Begin by importing the router library.

lib/app_component.dart (import)

import 'package:angular_router/angular_router.dart';

The router is not part of the Angular core, it is in its own library. The router is an optional service because not all applications need routing and, depending on your requirements, you may need a different routing library.

You teach the router how to navigate by configuring it with routes.

@RouteConfig

A router must be configured with a list of route definitions. A router also needs a host component, a point of origin for its navigations.

The @RouteConfig annotation combines the creation of a new router, its configuration, and its assignment to a host component in a single step.

@RouteConfig(const [ const Route( path: '/crisis-center', name: 'CrisisCenter', component: CrisisCenterComponent), const Route(path: '/heroes', name: 'Heroes', component: HeroesComponent) ]) class AppComponent {}

The @RouteConfig() is applied to AppComponent which makes it the router’s host component. The argument to @RouteConfig() is a list of route definitions.

Each definition is a Route which has a

  • path: the URL path segment for this route
  • name: the name of the route, which must be spelled in PascalCase to avoid possible confusion with the route path
  • component: the component associated with this route

The router draws upon its registry of definitions when the browser URL changes or when application code tells the router to navigate along a route path.

In simpler terms, you might say this of the first route:

  • When the browser’s location URL changes to match the path segment /crisis-center, then the router activates an instance of the CrisisCenterComponent and displays its view.

  • When the application requests navigation to the route named CrisisCenter, then the router activates an instance of CrisisCenterComponent, displays its view, and updates the browser’s address location and history with the URL for that path.

The AppComponent shell

AppComponent is the application shell. It has a title, a navigation bar with two links, and a router outlet where the router swaps views on and off the page. Here’s what you get:

Shell

The corresponding component template looks like this:

template: ''' <h1>Angular Router</h1> <nav> <a [routerLink]="['CrisisCenter']">Crisis Center</a> <a [routerLink]="['Heroes']">Heroes</a> </nav> <router-outlet></router-outlet> ''', styles: const ['.router-link-active {color: #039be5;}'],

RouterOutlet

The RouterOutlet is a directive from the router library that marks the spot in the template where the router should display the views for that outlet.

The <router-outlet> element is rendered in the DOM. The router inserts the outlet’s view elements as siblings immediately after the <router-outlet>.

Above the outlet, within the anchor tags, you see property bindings to RouterLink directives that look like [routerLink]="[...]". The template expression to the right of the equals is a link parameters list, and it holds the ingredients to router navigation:

  • the name of the route that prescribes the destination component and a path for the URL
  • optional route and query parameters that go into the route URL

The lists shown in the example above, each have a single parameter, a route name. You’ll see the use of route parameters later.

The RouterLink directive adds the router-link-active CSS class to active router link. This cascades down through each level of the route tree, so parent and child router links can be active at the same time.

Declaring router providers and directives

One way to let Angular know that your application is using router services is by adding ROUTER_PROVIDERS to your shell component’s providers list.

To use router directives like RouterLink and RouterOutlet within a component, add them individually to the component’s directives list, or for convenience you can add the ROUTER_DIRECTIVES list.

Here is the current state of app_component.dart which illustrates both of these additions:

lib/app_component.dart

import 'package:angular/angular.dart'; import 'package:angular_router/angular_router.dart'; import 'src/crisis_center_component_1.dart'; import 'src/heroes_component_1.dart'; @Component( selector: 'my-app', template: ''' <h1>Angular Router</h1> <nav> <a [routerLink]="['CrisisCenter']">Crisis Center</a> <a [routerLink]="['Heroes']">Heroes</a> </nav> <router-outlet></router-outlet> ''', styles: const ['.router-link-active {color: #039be5;}'], directives: const [ROUTER_DIRECTIVES], providers: const [ROUTER_PROVIDERS], ) @RouteConfig(const [ const Route( path: '/crisis-center', name: 'CrisisCenter', component: CrisisCenterComponent), const Route(path: '/heroes', name: 'Heroes', component: HeroesComponent) ]) class AppComponent {}

Application code

You’ve got a very basic, navigating app, one that can switch between two views when the user clicks a link. The starter app’s structure looks like this:

  • router_example
    • lib
      • app_component.dart
      • src
        • crisis_center_component.dart
        • heroes.component.dart
    • web
      • index.html
      • main.dart
      • styles.css

Here are the files discussed in this milestone

import 'package:angular/angular.dart'; import 'package:angular_router/angular_router.dart'; import 'src/crisis_center_component_1.dart'; import 'src/heroes_component_1.dart'; @Component( selector: 'my-app', template: ''' <h1>Angular Router</h1> <nav> <a [routerLink]="['CrisisCenter']">Crisis Center</a> <a [routerLink]="['Heroes']">Heroes</a> </nav> <router-outlet></router-outlet> ''', styles: const ['.router-link-active {color: #039be5;}'], directives: const [ROUTER_DIRECTIVES], providers: const [ROUTER_PROVIDERS], ) @RouteConfig(const [ const Route( path: '/crisis-center', name: 'CrisisCenter', component: CrisisCenterComponent), const Route(path: '/heroes', name: 'Heroes', component: HeroesComponent) ]) class AppComponent {} import 'package:angular/angular.dart'; @Component( selector: 'crisis-center', template: ''' <h2>Crisis Center</h2> <p>Get your crisis here</p> ''', ) class CrisisCenterComponent {} import 'package:angular/angular.dart'; @Component( selector: 'my-heroes', template: ''' <h2>Heroes</h2> <p>Get your heroes here</p> ''', ) class HeroesComponent {} <html> <head> <script> // WARNING: DO NOT set the <base href> like this in production! // Details: https://webdev.dartlang.org/angular/guide/router (function () { // App being served out of web folder (like WebStorm does)? var match = document.location.pathname.match(/^\/[-\w]+\/web\//); var href = match ? match[0] : '/'; document.write('<base href="' + href + '" />'); }()); </script> <title>Angular Router</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="styles.css"> <link rel="icon" type="image/png" href="favicon.png"> <script defer src="main.dart" type="application/dart"></script> <script defer src="packages/browser/dart.js"></script> </head> <body> <my-app>Loading...</my-app> </body> </html> import 'package:angular/angular.dart'; import 'package:router_example/app_component_1.dart'; void main() { bootstrap(AppComponent); }