Sunday, December 2, 2012

Routing: The Basics

Long gone are the days where a single web page had a single purpose of displaying some basic information.  But with ever more complex requirements of web application the page request with GET query string parameters becomes very cumbersome.  Routing is the solution to that problem.

In traditional server side request application, the request addressed is parsed and processed for string matches against predefined server routes.  In client side application, the same principle is applied, however the path is defined as a hash update to the address bar.

Example Application

GitHub: https://github.com/SergeiGolos/AngularStudent/tree/master/Routing/Example1

JSBin: http://jsbin.com/oteget/1/

The application renders a single page applications with multiple simple routes.

  • Home: which renders template of html and defaults from any unrecognized path.
  • About:  which renders a template controlled by a basic controller
  • Details: which renders a template controller by a controller with routing parameters.
Lets dive into to the code: HTML

We bootstrap our application with the ng-app directive, in this case our application is called example1, later we will see that the module which will define our routes and controllers will be named after this.  This is equivalent to name spacing, allowing multiple application to run on the page with out sharing scopes.

   1: <html ng-app="example1">

Much of the markup for this application is actually defining the application test harness, the navigation bar with the rendered links.  We will see more of this in the JavaScript sections where we define our MainCtrl.  The important section to notice in the controller is the <div> element with the ng-view directive.  This is the place holder for the routing targets, and where the angular routing magic occurs.  When we run the application it is that element which loads the template HTML and applies the the scope of the configured controller.


   1: <div ng-controller="MainCntl">
   2:     <div class="navbar navbar-fixed-top">
   3:         <div class="navbar-inner">
   4:             <div class="container">
   5:                 <a class="brand" 
   6:                     href="#/" 
   7:                     style="padding-top: 6px; padding-bottom: 0px;">Home</a>
   8:                 <ul class="nav">
   9:                     <li ng-repeat="link in links">
  10:                         <a href="#/{{link}}">{{link}}</a>
  11:                     </li>
  12:                 </ul>
  13:             </div>
  14:         </div>
  15:     </div>
  16:     <div style="margin-top:45px;">
  17:         <div ng-view/>
  18:     </div>
  19: </div>

Finally before we jump into the JavaScripts, a quick note about templates in angular.  Angular support both loading templates from a supporting template file by path and from script elements with an id name for the template being loaded.


The in html loaded format can be:  (notice the type of “text”/ng-template”)



   1: <script id="detailTemplate.html"
   2:            type="text/ng-template">
   1:  
   2:        Detail page, display template for detailId = {{test}}
   3:    
</script>

Lets dive into to the code: JavaScripts

Here is the meat and potatoes of the application.  Routing is defined here on initialization of the example1 application.



   1: var app = angular.module('example1', [], 
   2:     function($routeProvider) {
   3:         $routeProvider.when('/', { 
   4:             templateUrl: 'home.html' });
   5:         
   6:         $routeProvider.when('/About', {
   7:             templateUrl: 'about.html' ,  
   8:             controller : 'BasicPageCntl' });
   9:  
  10:         $routeProvider.when('/Details/:detailId', { 
  11:             templateUrl: 'detailTemplate.html', 
  12:             controller : 'DetailPageCntl'});            
  13:  
  14:         $routeProvider.otherwise({redirectTo: '/'});   
  15: });

To register the routes we invoke the when method on the $routeProvider object.  Lets take a deeper look at the 3 types of routes.



   1: $routeProvider.when('/', { templateUrl: 'home.html' });

Defines the default path.  The defined templateUrl points to a script tag on the index.html, but with no controller defined, this will simply render the defined template to the ng-view tag.



   1: $routeProvider.when('/About', {
   2:     templateUrl: 'about.html' ,  
   3:     controller : 'BasicPageCntl' });

Here the about.html is actually an external file.  While for the purposes of this example, the controller is empty.  In terms of the example, it is really no different then the default home route, but an actual scope is created. 



   1: $routeProvider.when('/Details/:detailId', { 
   2:             templateUrl: 'detailTemplate.html', 
   3:             controller : 'DetailPageCntl'}); 

The details route contains a parameter, defined as :detailId placeholder.  When the defined controller is created, the $routeParams argument is injected on the constructor.  The defined placeholder becomes a hash key.



   1: app.controller('DetailPageCntl', function($scope, $routeParams) { 
   2:     $scope.test = $routeParams["detailId"]; 
   3: });

Friday, November 23, 2012

A Humble Start

For almost two months I have promised myself a serious look at angular and what it can do for me in the corporate world.  But good examples are far and few between  There are many “hello world” and “Todo list” applications, but few real software engineering questions are left unanswered.

What about routing, with multiple controllers? What are the bests patterns for use of ng-view?  How do you dynamically create views with wired up dynamic controllers? In what way can DI be useful for a language with globals?

Ok, so maybe not so many questions out of the box, but as i find answers to some of the earlier questions more will crop up, and some of them may be questions others are asking.   Many of the technologies on the internet are learned though acts of kindness of strangers who post their experiments and learning experience into videos and blog posts.  This is hopefully my way of giving some of that back.