.l-main-section h2#section-route-use Using the Component Router p There are three steps to setting up routing with Angular's Component Router ol li Install the Component Router li Map paths to components li Link to routes .l-main-section h2#section-install-router Import the Component Router p. Create two files, index.html and app.ts, both at the root of the project: pre.prettyprint.lang-bash code. touch index.html app.ts p Your app directory should look something like: pre.prettyprint.lang-bash code. app.ts index.html package.json node_modules/ └── ... p. Because the component is an addition to the core, you must install Angular's Component Router into your app. When using the angular2.dev.js bundle you have include the additional router.dev.js bundle. p. Add Angular and Component Router into your app by adding the relevant <script> tags into your index.html: //ANGULAR 1 pre.prettyprint.lang-html.is-angular1.is-hidden code. <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <base href="/"> <title>My app</title> </head> <body ng-app="myApp" ng-controller="AppController as app"> <div ng-outlet></div> <script src="/node_modules/angular/angular.js"></script> <script src="/dist/router.es5.js"></script> <script src="/app/app.js"></script> </body> </html> pre.prettyprint.lang-html.is-angular2 code. <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <base href="/"> <title>My app</title> </head> <body ng-app="myApp" ng-controller="AppController as app"> <script src="https://jspm.io/system@0.16.js"></script> <script src="https://code.angularjs.org/2.0.0-alpha.21/angular2.dev.js"></script> <script src="https://code.angularjs.org/2.0.0-alpha.21/router.dev.js"></script> <script> System.import('main'); </script> </body> </html> p.is-angular2. Then you can add the router into your app by importing the Router module in your app.ts file: .code-box.is-angular2 pre.prettyprint.linenums.lang-typescript(data-name="typescript") code. import {Component, View, bootstrap} from 'angular2/angular2'; import {Router, RouterOutlet, RouterLink} from 'angular2/router'; pre.prettyprint.linenums.lang-javascript(data-name="es5") code. // self-executing bundle deploys angular APIs on the window object. window.angular; // the router APIs are part of the router sub-object. window.angular.router; p.is-angular1.is-hidden. This is a pretty typical angular app, except the ng-outlet directive. ng-outlet is like ng-view; it's a placeholder for part of your app loaded dynamically based on the route configuration. p.is-angular2. This is the same as you've seen in the rest of Angular 2, except the router-outlet directive. router-outlet is a placeholder for part of your app loaded dynamically based on the route configuration. p So how do we configure the app? Let's open app.ts and find out. Add this to the file: //ANGULAR 1 pre.prettyprint.lang-javascript.is-angular1.is-hidden code. angular.module('app', ['ngNewRouter']) .controller('AppController', ['$router', AppController]); AppController.$routeConfig = [ {path: '/', component: 'home' } ]; function AppController ($router) {} // ANGULAR 2 .code-box pre.prettyprint.linenums.lang-typescript(data-name="typescript") code. import {Component, View, bootstrap} from 'angular2/angular2'; import {routerInjectables, RouterOutlet} from 'angular2/router'; import {HomeComp} from './components/home'; @Component({ selector: 'my-app' }) @View({ template: '<router-outlet></router-outlet>', directives: [RouterOutlet] }) @RouteConfig([ {path: '/', component: HomeComp } ]) class AppComp {} bootstrap(AppComp, routerInjectables); pre.prettyprint.linenums.lang-javascript(data-name="es5") code. var HomeComp = function() {}; ... var AppComp = function() {}; AppComp.annotations = [ new angular.ComponentAnnotation({ selector: 'my-app' }), new angular.ViewAnnotation({ template: '<router-outlet></router-outlet>', directives: [angular.router.RouterOutlet] }), new angular.router.RouteConfigAnnotation([ {path: '/', component: HomeComp} ]) ]; angular.bootstrap(AppComp, routerInjectables); p.is-angular1.is-hidden. The ngComponentRouter module provides a new service, $router. In the configuration, we map paths to components. What's a component? Let's talk about that for a bit. p.is-angular2. The angular2/router module provides routerInjectables, which is an array of all of the services you'll need to use the component router in your app. .l-main-section h2#section-map-paths-to-components Map paths to components //- TODO - Alex - would it make more sense to have some paragraph styles conditionalized like this?? p.angular1.is-hidden. In Angular 1, a "routable component" is a template, plus a controller, plus a router. You can configure how to map component names to controllers and templates in the $componentLoader service. p. A component's template can have "outlets," which are holes in the DOM for loading parts of your app based on the route configuration and it can ask the DI system for an instance of Router. A component's router tells the component what to put inside the outlets based on URL. The configuration maps routes to components for each outlet. p Let's make a home component that our app can route to: pre.prettyprint.lang-bash code. mkdir -p components/home touch components/home/home.html components/home/home.js p This creates our component directory and its corresponding files: a template and a JavaScript component. p Let's open home.html and add some content: pre.prettyprint.lang-html code. <h1>Hello {{home.name}}!</h1> p.is-angular1.is-hidden. Components use the "controller as" syntax, so if we want to access property name of the controller, we write the binding as home.name. p Let's make a controller: //ANGULAR 1 pre.prettyprint.lang-javascript.is-angular1.is-hidden code. angular.module('app.home', []) .controller('HomeController', [function () { this.name = 'Friend'; }]); // ANGULAR 2 .code-box pre.prettyprint.linenums.lang-typescript(data-name="typescript") code. @Component({ selector: 'home-cmp' }) @View({ template: 'Hello {{name}}' }) export class HomeComponent { name:string; constructor() { this.name = 'Friend'; } } pre.prettyprint.linenums.lang-javascript(data-name="es5") code. function HomeComponent() { this.name = 'Friend'; } AppComponent.annotations = [ new angular.ComponentAnnotation({ selector: 'home-cmp' }), new angular.ViewAnnotation({ template: 'Hello {{name}}' }) ]; p.is-angular1.is-hidden. To wire this up, we need to add a <script> tag to our index.html: pre.prettyprint.lang-html code. ... <script src="./components/home/home.js"></script> //ANGULAR 1 p.is-angular1.is-hidden. And add the controller's module as a dependency to our main module in app.js: pre.prettyprint.lang-javascript.is-angular1.is-hidden code. angular.module('app', ['ngNewRouter', 'app.home']) .controller('AppController', ['$router', AppController]); // ... p. To wire this up, we need to import the component into the rest of our app. // ANGULAR 2 .code-box.is-angular2 pre.prettyprint.linenums.lang-typescript(data-name="typescript") code. import {HomeComp} from './components/home'; pre.prettyprint.linenums.lang-javascript(data-name="es5") code. // Use your favorite module system / bundler for ES5. p If you load up the app, you should see Hello Friend! .l-main-section h2#section-link-to-routes Link to routes p Let's add another route and then link to it. This route will have a route parameter, id. p In app.js: //ANGULAR 1 pre.prettyprint.lang-javascript.is-hidden code. angular.module('app', ['ngNewRouter']) .controller('AppController', ['$router', AppController]); AppController.$routeConfig = [ { path: '/', component: 'home' }, { path: '/detail/:id', component: 'detail' } ]; function AppController ($router) {} // ANGULAR 2 .code-box pre.prettyprint.linenums.lang-typescript(data-name="typescript") code. ... @RouteConfig([ { path: '/', component: HomeComp }, { path: '/detail/:id', component: DetailComp } ]) class AppComp {} pre.prettyprint.linenums.lang-javascript(data-name="es5") code. var AppComp = function() {}; AppComp.annotations = [ ... new angular.router.RouteConfigAnnotation([ { path: '/', component: HomeComp} { path: '/detail/:id', component: DetailComp } ]) ]; angular.bootstrap(AppComp, routerInjectables); p. We can link to our detail component using the router-link directive. Add this to template: pre.prettyprint.lang-html.is-angular1.is-hidden. code. <body ng-app="myApp" ng-controller="AppController as app"> <a ng-link="detail({id: 5})">link to detail</a> ... pre.prettyprint.lang-html.is-angular2 code. <a ng-link="detail({id: 5})">link to detail</a> p This directive will generate an href and update the browser URL. p We should also implement our detail component. Let's make these new files: pre.prettyprint.lang-bash code. mkdir components/detail touch components/detail/detail.html components/detail/detail.ts p In detail.ts, we implement a controller that uses the id route parameter: //ANGULAR 1 pre.prettyprint.lang-javascript.is-hidden code. angular.module('app.detail', ['ngNewRouter']) .controller('DetailController', ['$routeParams', DetailController]); function DetailController ($routeParams) { this.id = $routeParams.id; } // ANGULAR 2 .code-box pre.prettyprint.linenums.lang-typescript(data-name="typescript") code. @Component({ selector: 'detail-cmp' }) @View({ template: 'User ID: {{id}}' }) export class DetailComp { id: string; constructor(routeParams:RouteParams) { this.id = routeParams.get('id'); } } pre.prettyprint.linenums.lang-javascript(data-name="es5") code. function DetailComp(routeParams) { this.id = routeParams.get('id'); } DetailComp.annotations = [ new angular.ComponentAnnotation({ selector: 'detail-cmp' }), new angular.ViewAnnotation({ template: 'User ID: {{id}}' }) ]; DetailComp.parameters = [[RouteParams]]; p.is-angular1.is-hidden. And then we can display the id in our template by adding this to detail.html: pre.prettyprint.lang-html.is-angular1.is-hidden code. <p>detail {{detail.id}}</p> p.is-angular1.is-hidden. Finally, we'd wire up the controller by adding a script tag and making our app module depend on app.detail. .l-main-section h2#section-configuring-the-router Configuring the Router p. Unlike other routing systems, Component Router maps URLs to components. A router takes an array of pairings like this: //ANGULAR 1 pre.prettyprint.lang-javascript.is-angular1.is-hidden code. //ES5 MyController.$routeConfig = [ { path: '/user', component: 'user' } ]; //ANGULAR 2 .code-box.is-angular2 pre.prettyprint.linenums.lang-javascript(data-name="typescript") code. @Component() @View() @RouteConfig([ { path: '/user', component: UserComponent } ]) class MyComp {} pre.prettyprint.linenums.lang-javascript(data-name="es5") code. function MyComp() {}; MyComp.annotations = [ new angular.ComponentAnnotation({ ... }), new angular.ViewAnnotation({ ... }), new angular.router.RouteConfigAnnotation([ {path: '/', component: UserComponent} ]) .l-sub-section h3#section-sibling-outlets Sibling Outlets p You can configure multiple outlets on the same path like this: //ANGULAR 1 .codebox.is-angular1.is-hidden pre.prettyprint.linenums.lang-javascript(data-name="es5") code. //ES5 MyController.$routeConfig = [ { path: '/user', components: { master: 'userList', detail: 'user' } } ]; pre.prettyprint.linenums.lang-html(data-name="html") code. //HTML <div ng-outlet="master"></div> <div ng-outlet="detail"></div> //ANGULAR 2 .code-box.is-angular2 pre.prettyprint.linenums.lang-typescript(data-name="typescript") code. //TypeScript @Component({}) @View({ template: `<div router-outlet="master"></div> <div router-outlet="detail"></div>`, directives: [RouterOutlet, RouterLink] }) @RouteConfig({ path: '/user', components: { master: UserListComp, detail: UserComp } }) class MyComponent {} pre.prettyprint.linenums.lang-javascript(data-name="es5") code. function MyComponent() {}; MyComponent.annotations = [ new angular.ComponentAnnotation({ ... }), new angular.ViewAnnotation({ template: '<div router-outlet="master"></div>' + '<div router-outlet="detail"></div>', directives: [RouterOutlet] }), new angular.router.RouteConfigAnnotation([{ path: '/user', components: { master: UserComponent, detail: UserComp } }]) ]; p You can link to any sibling just as you normally would: //ANGULAR 1 pre.prettyprint.linenums.lang-html.is-angular1.is-hidden code. //HTML <p>These both link to the same view:</p> <a ng-link="userList">link to userList</a> <a ng-link="user">link to user component</a> //ANGULAR 2 pre.prettyprint.linenums.lang-html.is-angular2 code. //HTML <p>These both link to the same view:</p> <a router-link="userList">link to userList</a> <a router-link="user">link to user component</a> p Or, you can explicitly link to a outlet-component pair like this: //ANGULAR 1 pre.prettyprint.linenums.lang-html.is-angular1.is-hidden code. //HTML <p>These both link to the same view:</p> <a ng-link="master:userList">link to userList</a> <a ng-link="detail:user">link to user component</a> //ANGULAR 2 pre.prettyprint.linenums.lang-html.is-angular2 code. //HTML <p>These both link to the same view:</p> <a router-link="master:userList">link to userList</a> <a router-link="detail:user">link to user component</a> .l-sub-section h3#section-redirecting-routes Redirecting routes p You can use `redirectTo` for migrating to a new URL scheme and setting up default routes. p. For example, as specified below, when a user navigates to `/`, the URL changes to `/user` and the outlet at that level loads the `user` component. //ANGULAR 1 pre.prettyprint.linenums.lang-javascript.is-angular1.is-hidden(data-name="es5") code. //ES5 MyController.$routeConfig = [ { path: '/', redirectTo: '/user' }, { path: '/user', component: 'user' } ]; function MyController() {} //ANGULAR 2 .code-box.is-angular2 pre.prettyprint.linenums.lang-typescript(data-name="typescript") code. //TypeScript @Component({}) @View({ directives: [RouterOutlet] }) @RouteConfig([ { path: '/', redirectTo: '/user' }, { path: '/user', component: UserComp } ]) class MyComp {} pre.prettyprint.linenums.lang-javascript(data-name="es5") code. function MyComponent() {}; MyComponent.annotations = [ new angular.ComponentAnnotation({ ... }), new angular.ViewAnnotation({ directives: [RouterOutlet] }), new angular.router.RouteConfigAnnotation([ { path: '/user', component: UserComp } { path: '/', redirectTo: '/user' }, ]) ]; .l-sub-section h3#section-aliases Aliases p. When linking to a route, you normally use the name of the component. You can also specify an alias to use instead. p Consider the following route configuration: //ANGULAR 1 pre.prettyprint.linenums.lang-javascript.is-angular1.is-hidden(data-name="es5") code. //ES5 MyController.$routeConfig = [ { path: '/', component: 'user' } ]; //ANGULAR 2 .code-box.is-angular2 pre.prettyprint.linenums.lang-typescript(data-name="typescript") code. //TypeScript @Component({ selector: 'my-comp' }) @View({ directives: [RouterOutlet] }) @RouteConfig([ { path: '/', component: UserComp } ]) class MyComp {} pre.prettyprint.linenums.lang-javascript(data-name="es5") code. function MyComp() {}; MyComp.annotations = [ new angular.ComponentAnnotation({ ... }), new angular.ViewAnnotation({ directives: [RouterOutlet] }), new angular.router.RouteConfigAnnotation([ { path: '/', component: UserComp } ]) ]; p We can link to the route in our template with the name of the component: //ANGULAR 1 pre.prettyprint.linenums.lang-html.is-angular1.is-hidden code. //HTML <a ng-link="user">link to user component</a> //ANGULAR 2 pre.prettyprint.linenums.lang-html code. //HTML <a router-link="user">link to user component</a> p Or, we can define an alias myUser like this: //ANGULAR 1 pre.prettyprint.linenums.lang-javascript.is-angular1.is-hidden(data-name="es5") code. //ES5 MyController.$routeConfig = [ { path: '/', component: 'user', as: 'myUser' } ]; //ANGULAR 2 .code-box.is-angular2 pre.prettyprint.linenums.lang-typescript(data-name="typescript") code. //TypeScript @Component() @View() @RouteConfig([ { path: '/', component: UserComp, as: 'myUser' } ]) class MyComp {} pre.prettyprint.linenums.lang-javascript(data-name="es5") code. //ES5 //TODO: Need Angular 2 ES5 Example here p And refer instead to the alias for the component in our template, with the same end-result: //ANGULAR 1 pre.prettyprint.linenums.lang-html.is-angular1.is-hidden code. //HTML <a ng-link="myUser">link to user component</a> //ANGULAR 2 pre.prettyprint.linenums.lang-html code. //HTML <a router-link="myUser">link to user component</a> p. This is especially useful when you have sibling components, but want to refer to an entire level of routing in your controller. For example: //ANGULAR 1 pre.prettyprint.linenums.lang-javascript.is-angular1.is-hidden(data-name="es5") code. //ES5 MyController.$routeConfig = [ { path: '/', components: { master: 'userList', detail: 'user' }, as: 'myUser' } ]; //ANGULAR 2 .code-box.is-angular2 pre.prettyprint.linenums.lang-typescript(data-name="typescript") code. //TypeScript @RouteConfig([ { path: '/', components: { master: UserListComp, detail: UserComp }, as: 'myUser' } ]) pre.prettyprint.linenums.lang-javascript(data-name="es5") code. new angular.router.RouteConfigAnnotation([ { path: '/', components: { master: UserListComp, detail: UserComp }, as: 'myUser' } ]) //- TODO(btford): expand on this. .l-sub-section h3#dynamic-configuration Dynamic Configuration p.is-angular2. You can configure dynamic routing by asking the DI system for a Router. p.is-angular1.is-hidden You can configure dynamic routing by making a request for $router.