# AngularJS - Routing ## Lesson Objectives 1. Describe Push State 1. Set up your HTML with propper tags and directives 1. Write initial JS 1. Write a basic route 1. Use url params 1. Create route specific variables 1. Create a default route 1. Use extended features of templates ## Describe Push State You can update the browser's url without refreshing the page using JS - this is called Push State. It's part of HTML5 - up until recently, the only way to update the url is make a new request - click a link - type into browser's url bar and hit enter - now you can do that with javascript What can Angular do with this? - angular will listen for changes in the url - next, angular will render a template into a specific part of the page that we define - it will then attach a controller to this template and alias it `as` a variable which can be referenced in the HTML ## Set up your HTML with proper tags and directives - We need to include Angular and ngRoute, which is a separate file - This approach is similar to express, where functionality that is not crucial is moved to separate packages (ejs, method-override, etc...) file: index.html ```html ``` Next, tell angular where to render the templates with the `ng-view` directive ```html
``` We need to make sure all links are relative to a specific base url (/ in this case). Add the following: ```html ```
file: index.html ```html
```
Links that start with `http` will not use push state. Everything else will. file: index.html ```html
``` ## Write initial JS We need one dependency for our module file: js/app.js ```javascript const myApp = angular.module('MyApp', ['ngRoute']); ``` Add `ng-app="MyApp"` to the `` tag in your html
index.html ```html
```
We need to create a `config` for our module to make this work. A module config runs only once at load time. file: js/app.js ```javascript const myApp = angular.module('MyApp', ['ngRoute']); myApp.config(function() { //.config just runs once on load. Looks like a controller, but without a name }); ``` Let's add two important services - `$locationProvider` handles push state - push state - allows you to update the URL in your browser without reloading the page - also updates your history when URL changes via push state - `$routeProvider` creates event listeners which render a template into ng-view when the browser URL matches its URL file: js/app.js ```javascript //include $routeProvider and $locationProvider const myApp = angular.module('MyApp', ['ngRoute']); myApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) { //.config just runs once on load $locationProvider.html5Mode({ enabled: true }); // tell angular to use push state }]); ``` ## Write a basic route Now let's add a basic route within the config function, after `$locationProvider.html5Mode({ enabled: true });`. ```javascript $routeProvider.when('/url1', { //when http://localhost:3000/url1 templateUrl: 'partials/partial1.html', // render http://localhost:3000/partials/partial1.html controller: function(){ // attach controller //controller code goes here }, controllerAs: 'ctrl' // alias for controller (like ng-controller="Ctrl1 as ctrl") }); ```
file: js/app.js ```javascript const myApp = angular.module('MyApp', ['ngRoute']); myApp.controller('Ctrl1', function(){ }); myApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) { //.config just runs once on load $locationProvider.html5Mode({ enabled: true }); // tell angular to use push state $routeProvider.when('/url1', { //when http://localhost:3000/url1 templateUrl: 'partials/partial1.html', // render http://localhost:3000/partials/partial1.html controller: function(){ // attach controller //controller code goes here this.foo = 'bar' }, controllerAs: 'ctrl' // alias for controller (like ng-controller="Ctrl1 as ctrl") }); }]); ```
add the file: partials/partial1.html ```html Controller foo var: {{ctrl.foo}} ``` - Now when you click the "url1 with no param" text, you should see the partial appear in the appropriate place - Note, if you refresh the page after clicking the link, you'll get a file not found - That's because there's no file called `url1` - You'll have to tell express to serve up your index.html file for that route ```javascript app.get('/url1', (req, res)=>{ res.render('/public/index.html') //note the initial / so it doesn't go into views }) ``` ## Use url params We can access url params with a pattern that is similar to express: ```javascript $routeProvider.when('/url1/:id', { //when http://localhost:3000/url1/:id - :id is a param just like in express templateUrl: 'partials/partial2.html', controller: 'Ctrl2', controllerAs: 'ctrl' }); ```
file: js/app.js ```javascript const myApp = angular.module('MyApp', ['ngRoute']); myApp.controller('Ctrl1', function(){ }); myApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) { //.config just runs once on load $locationProvider.html5Mode({ enabled: true }); // tell angular to use push state $routeProvider.when('/url1', { //when http://localhost:3000/url1 templateUrl: 'partials/partial1.html', // render http://localhost:3000/partials/partial1.html controller: 'Ctrl1', // attach controller Ctrl1 controllerAs: 'ctrl' // alias for Ctrl1 (like ng-controller="Ctrl1 as ctrl") }); $routeProvider.when('/url1/:id', { //when http://localhost:3000/url1/:id - :id is a param just like in express templateUrl: 'partials/partial2.html', controller: 'Ctrl2', controllerAs: 'ctrl' }); }]); ```
file: index.html ```html
```
Inside the controller, we can access those url params: ```javascript myApp.controller('Ctrl2', ['$routeParams', function ($routeParams) { this.id = $routeParams.id; //access :id from url }]); ```
file: js/app.js ```javascript //include $routeParams service const myApp = angular.module('MyApp', ['ngRoute']); myApp.controller('Ctrl1', function(){ }); myApp.controller('Ctrl2', ['$routeParams', function ($routeParams) { this.id = $routeParams.id; //access :id from url }]); myApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) { //.config just runs once on load $locationProvider.html5Mode({ enabled: true }); // tell angular to use push state $routeProvider.when('/url1', { //when http://localhost:3000/url1 templateUrl: 'partials/partial1.html', // render http://localhost:3000/partials/partial1.html controller: 'Ctrl1', // attach controller Ctrl1 controllerAs: 'ctrl' // alias for Ctrl1 (like ng-controller="Ctrl1 as ctrl") }); $routeProvider.when('/url1/:id', { //when http://localhost:3000/url1/:id - :id is a param just like in express templateUrl: 'partials/partial2.html', controller: 'Ctrl2', controllerAs: 'ctrl' }); }]); ```
file: partials/partial2.html ```html {{ctrl.id}} ```
## Create route specific variables We can create a variable for a specific route: ```javascript $routeProvider.when('/url3', { //... some code someVarSpecificToThisRoute: 'weeee' // you can pass variables into the controller here if you'd like //...some code }); ```
file: js/app.js ```javascript const myApp = angular.module('MyApp', ['ngRoute']); myApp.controller('Ctrl1', function(){ }); myApp.controller('Ctrl2', ['$routeParams', function ($routeParams) { this.id = $routeParams.id; //access :id from url }]); myApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) { //.config just runs once on load $locationProvider.html5Mode({ enabled: true }); // tell angular to use push state $routeProvider.when('/url1', { //when http://localhost:3000/url1 templateUrl: 'partials/partial1.html', // render http://localhost:3000/partials/partial1.html controller: 'Ctrl1', // attach controller Ctrl1 controllerAs: 'ctrl' // alias for Ctrl1 (like ng-controller="Ctrl1 as ctrl") }); $routeProvider.when('/url1/:id', { //when http://localhost:3000/url1/:id - :id is a param just like in express templateUrl: 'partials/partial2.html', controller: 'Ctrl2', controllerAs: 'ctrl' }); $routeProvider.when('/url3', { templateUrl: 'partials/partial3.html', controller: 'Ctrl3', controllerAs: 'ctrl', someVarSpecificToThisRoute: 'weeee' // you can pass variables into the controller here if you'd like }); }]); ```
And access it in the controller: ```javascript myApp.controller('Ctrl2', ['$routeParams', function ($routeParams) { this.id = $routeParams.id; //access :id from url }]); ```
file: js/app.js ```javascript const myApp = angular.module('MyApp', ['ngRoute']); myApp.controller('Ctrl1', function(){ }); myApp.controller('Ctrl2', ['$routeParams', function ($routeParams) { this.id = $routeParams.id; //access :id from url }]); myApp.controller('Ctrl3', ['$route', function ($route) { this.funVar = $route.current.someVarSpecificToThisRoute; //you can access variables created in the when action like this }]); myApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) { //.config just runs once on load $locationProvider.html5Mode({ enabled: true }); // tell angular to use push state $routeProvider.when('/url1', { //when http://localhost:3000/url1 templateUrl: 'partials/partial1.html', // render http://localhost:3000/partials/partial1.html controller: 'Ctrl1', // attach controller Ctrl1 controllerAs: 'ctrl' // alias for Ctrl1 (like ng-controller="Ctrl1 as ctrl") }); $routeProvider.when('/url1/:id', { //when http://localhost:3000/url1/:id - :id is a param just like in express templateUrl: 'partials/partial2.html', controller: 'Ctrl2', controllerAs: 'ctrl' }); $routeProvider.when('/url3', { templateUrl: 'partials/partial3.html', controller: 'Ctrl3', controllerAs: 'ctrl', someVarSpecificToThisRoute: 'weeee' // you can pass variables into the controller here if you'd like }); }]); ```
add link in index.html: ```html
```
create partials/partial3.html ```html {{ctrl.funVar}} ```
## Create a default route Lastly, you can create a default route. Note at any point, you don't have to have a controller/partial combo. You can also have just a redirect property: ```javascript $routeProvider.otherwise({ // if browser url doesn't match any of the above... //here you can do something like above if you'd like with a template and a controller redirectTo: '/' // or you can redirect to another url. //redirection can happen in any 'when' action; I just happened to do it here. I could have put it in one of the above sections too }); ```
file: js/app.js ```javascript const myApp = angular.module('MyApp', ['ngRoute']); myApp.controller('Ctrl1', function(){ }); myApp.controller('Ctrl2', ['$routeParams', function ($routeParams) { this.id = $routeParams.id; //access :id from url }]); myApp.controller('Ctrl3', ['$route', function ($route) { this.funVar = $route.current.someVarSpecificToThisRoute; //you can access variables created in the when action like this }]); myApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) { //.config just runs once on load $locationProvider.html5Mode({ enabled: true }); // tell angular to use push state $routeProvider.when('/url1', { //when http://localhost:3000/url1 templateUrl: 'partials/partial1.html', // render http://localhost:3000/partials/partial1.html controller: 'Ctrl1', // attach controller Ctrl1 controllerAs: 'ctrl' // alias for Ctrl1 (like ng-controller="Ctrl1 as ctrl") }); $routeProvider.when('/url1/:id', { //when http://localhost:3000/url1/:id - :id is a param just like in express templateUrl: 'partials/partial2.html', controller: 'Ctrl2', controllerAs: 'ctrl' }); $routeProvider.when('/url2', { templateUrl: 'partials/partial3.html', controller: 'Ctrl3', controllerAs: 'ctrl', someVarSpecificToThisRoute: 'weeee' // you can pass variables into the controller here if you'd like }); $routeProvider.otherwise({ // if browser url doesn't match any of the above... //here you can do something like above if you'd like with a template and a controller redirectTo: '/' // or you can redirect to another url. //redirection can happen in any 'when' action; I just happened to do it here. I could have put it in one of the above sections too }); }]); ```
create a route that doesn't match any predefined url: ```html
  • bad url
  • ````
    file: index.html ```html
    ```
    ## Use extended features of templates ### Script tag templates You can have a template inside a script tag instead of an external file. - the advantage to this is that it doesn't need to make an extra http request to get the template - the downside is that your html gets more bloated ```html ```
    file: index.html ```html
    ```
    file: js/app.js ```javascript const myApp = angular.module('MyApp', ['ngRoute']); myApp.controller('Ctrl1', function(){ }); myApp.controller('Ctrl2', ['$routeParams', function ($routeParams) { this.id = $routeParams.id; //access :id from url }]); myApp.controller('Ctrl3', ['$route', function ($route) { this.funVar = $route.current.someVarSpecificToThisRoute; //you can access variables created in the when action like this }]); myApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) { //.config just runs once on load $locationProvider.html5Mode({ enabled: true }); // tell angular to use push state $routeProvider.when('/url1', { //when http://localhost:3000/url1 templateUrl: 'partials/partial1.html', // render http://localhost:3000/partials/partial1.html controller: 'Ctrl1', // attach controller Ctrl1 controllerAs: 'ctrl' // alias for Ctrl1 (like ng-controller="Ctrl1 as ctrl") }); $routeProvider.when('/url1/:id', { //when http://localhost:3000/url1/:id - :id is a param just like in express templateUrl: 'partials/partial2.html', controller: 'Ctrl2', controllerAs: 'ctrl' }); $routeProvider.when('/url2', { templateUrl: 'partials/partial3.html', controller: 'Ctrl3', controllerAs: 'ctrl', someVarSpecificToThisRoute: 'weeee' // you can pass variables into the controller here if you'd like }); $routeProvider.when('/url4', { templateUrl: 'partials/partial4.html' }) $routeProvider.otherwise({ // if browser url doesn't match any of the above... //here you can do something like above if you'd like with a template and a controller redirectTo: '/' // or you can redirect to another url. //redirection can happen in any 'when' action; I just happened to do it here. I could have put it in one of the above sections too }); }]); ```
    create link in index.html ```html
    ```
    ### Sub Partials You can have includes inside templates. file: partials/partial5.html ```html template 5
    ```
    create a route handler in js/app.js: ```javascript const myApp = angular.module('MyApp', ['ngRoute']); myApp.controller('Ctrl1', function(){ }); myApp.controller('Ctrl2', ['$routeParams', function ($routeParams) { this.id = $routeParams.id; //access :id from url }]); myApp.controller('Ctrl3', ['$route', function ($route) { this.funVar = $route.current.someVarSpecificToThisRoute; //you can access variables created in the when action like this }]); myApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) { //.config just runs once on load $locationProvider.html5Mode({ enabled: true }); // tell angular to use push state $routeProvider.when('/url1', { //when http://localhost:3000/url1 templateUrl: 'partials/partial1.html', // render http://localhost:3000/partials/partial1.html controller: 'Ctrl1', // attach controller Ctrl1 controllerAs: 'ctrl' // alias for Ctrl1 (like ng-controller="Ctrl1 as ctrl") }); $routeProvider.when('/url1/:id', { //when http://localhost:3000/url1/:id - :id is a param just like in express templateUrl: 'partials/partial2.html', controller: 'Ctrl2', controllerAs: 'ctrl' }); $routeProvider.when('/url2', { templateUrl: 'partials/partial3.html', controller: 'Ctrl3', controllerAs: 'ctrl', someVarSpecificToThisRoute: 'weeee' // you can pass variables into the controller here if you'd like }); $routeProvider.when('/url4', { templateUrl: 'partials/partial4.html' }) $routeProvider.when('/url5', { templateUrl: 'partials/partial5.html' }) $routeProvider.otherwise({ // if browser url doesn't match any of the above... //here you can do something like above if you'd like with a template and a controller redirectTo: '/' // or you can redirect to another url. //redirection can happen in any 'when' action; I just happened to do it here. I could have put it in one of the above sections too }); }]); ```
    add a link in index.html: ```html
    ```