AngularJS Routing

In this post I am going to talk about anuglarJS routing.We will develop a small sample application so that we can get a good idea of how to implement routing.

In a normal web application different content is represented by  different url and you can bookmark these url for reaching these pages.In SPA  (Single page application) routes enable you to create different url for different content.The base url remains the same and the ‘client fragment’ portion of the url changes based on the routes.OK.Lets make it clearer…

Suppose we have forum kind of application with url http://sitename/page.html which lands you to the home page of the application.Now we can show users different views (basically different content) for different routes which are represented by the portion which comes after the ‘#’ in the url. So we can havehttp://sitename/page.html#/Posts for showing posts,http://sitename/page.html#/Posts/Comments  for showing comments for a particular post etc and this all happens on the client side.Routing allows you to swap different views based on the route.

For our application we will use below structure.

layout

Layout View  will be a master view / master page which will have a list of users in the top half part and bottom half will be the place holder where different views will be presented as shown below.

image

Also for this application we will be using JSONPlaceHolder api which is just a fake rest api available online and is quite handy in case you want to do some JSON + REST API testing.

Here is the url for the working application where you can play with it and see the source code . (For those who want to see the stuff first and then see how it was built:-))

Pre-requisites

pl
To follow this post I am assuming you are having basic knowledge of AngularJS concepts like scope,controllers,services etc.If not you can visit my earlier post on developing you first AngularJS application.Also you can take this pluralsight course on getting started with Angular JS by Scott Allen.

First lets have  index.html file based on AngularJS template as shown below.This will act as a layout page or  master page (similar to master pages in asp.net)which will be displayed for all the views.Below file has markup to show list of users and MainController defined below has logic for fetching list of users through API call.

Index.html

<!DOCTYPE html>
<html ng-app="RoutingApp">

<head>
  <script data-require="angular.js@*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
  <script data-require="angular-route@1.2.20" data-semver="1.2.20" src="https://code.angularjs.org/1.2.20/angular-route.js"></script>
  <script src="app.js"></script>
  <script src="MainController.js"></script>
  <link rel="stylesheet" href="style.css" />
</head>

<body ng-controller="MainController">
  {{info}}

  <div class="divTable">
    <div class="divRow">
      <div class="divHeader">Employee Name</div>
      <div class="divHeader">User Name</div>
      <div class="divHeader">Email</div>
    </div>
    <div class="divRow" ng-repeat="user in users track by $index">
      <div class="divCell"><a href="#">{{user.name}}</a>
      </div>
      <div class="divCell">{{user.username}}</div>
      <div class="divCell">{{user.email}}</div>
    </div>

  </div>
  <div>
  </div>

</body>

</html>

Note that we are including “angular-route.js” file as routing functionality does not come by default with “angular.js” file and have to be added separately.

As shown above we will be having a module called “RoutingApp” which is given as value for ng-app directive and  a controller “MainController” to start with.

MainController.js

var MainController = function($scope, $http) {

  console.log("MainController");

  var onUsersSuccess = function(response) {
    console.log("onUsersSuccess");
    $scope.users = response.data;

  };

  var onUsersError = function() {
    $scope.info = "Error retrieving User data";
  };

  $http.get("http://jsonplaceholder.typicode.com/users")
    .then(onUsersSuccess, onUsersError);

};

//Register controller with module
app.controller("MainController", MainController);

In main controller we are calling JSONPlaceholder api to get list of all users.

Also below is the basic CSS I am using to show some table formatting using divs.

style.css

.divTable{
  display:table;
  width:auto;
  background-color:#eee;
  border:1px solid  #666666;
  border-spacing:5px;/*cellspacing:poor IE support for  this*/
}
.divRow{
  display:table-row;
  width:auto;
  clear:both;
}
.divCell{
  float:left;/*fix for  buggy browsers*/
  display:table-column;
  width:200px;
  background-color:#ccc;
}
.divHeader{
  float:left;/*fix for  buggy browsers*/
  display:table-column;
  width:200px;
  background-color:Gray;
  font-weight:bold;
  color:white;
}

.details {
  width:90%;
    border: 2px solid;
    border-radius: 25px;
    padding:20px;
    background-color:#ccc;
}

Configuring Routes using $routeProvider

Lets create a file called “app.js” where we will define our “RoutingApp” module and have all the routing configuration.

app.js

(function(){
app = angular.module("RoutingApp", ['ngRoute']);

var configurationFuntion = function($routeProvider) {
  $routeProvider.
  when('/users', {
      templateUrl: 'users.html',
    }).
    when('/users/:userId',{
       templateUrl : 'userdetails.html',
       controller : 'DetailsController'
    }).
     when('/posts/:userName/:userId',{
       templateUrl : 'posts.html',
       controller : 'PostController'
    }).
     otherwise({
        redirectTo: '/users'
     });
  }

  app.config(['$routeProvider', configurationFuntion]);
})();

Ok. First thing to note in above code is while creating our module we are referring ‘ngRoute’ module which provides functionality for routing and is available through angular-routing.js.

Routes in AngularJS are configured using $routeProvider ( which is provider for for $route  service).$routeProvider is used to link url ,View template and Controller.

We use $routeProvider.when() to provide url pattern that when matched will render view specified by templateUrl  argument which will have controller specified with controller  argument.In case none of the patterns match control goes to .otherwise  and url mentioned in redirectTo argument is used.For example if you are using ‘/users’ as route pattern it will match http://<baseurl>/#/users.On the other hand if you want to parametrize the url you can use ‘:<parameter>’  e.g. ‘/users/:userName/:userId’  as route pattern will match http://<baseurl>/#/users/Larry/1, http://<baseurl>/#/users/Ray/12, http://<baseurl>/#/users/jags/e12334 etc.

At this point we should be able to run our application to at least see how layout view will be rendered.

image

ngView

Now lets do some plumbing for showing our views in our layout template.For this we use ng-view  directive.Its very simple ,whichever html element is added with ng-view  directive it becomes container for the view templates.So for our application we will add ng-view  directive on div tag as shown below.

<!DOCTYPE html>
<html ng-app="RoutingApp">

<head>
  <script data-require="angular.js@*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
  <script data-require="angular-route@1.2.20" data-semver="1.2.20" src="https://code.angularjs.org/1.2.20/angular-route.js"></script>
  <script src="app.js"></script>
  <script src="MainController.js"></script>
  <link rel="stylesheet" href="style.css" />
</head>

<body ng-controller="MainController">
  {{info}}

  <div class="divTable">
    <div class="divRow">
      <div class="divHeader">Employee Name</div>
      <div class="divHeader">User Name</div>
      <div class="divHeader">Email</div>
    </div>
    <div class="divRow" ng-repeat="user in users track by $index">
      <div class="divCell"><a href="#/users/{{user.id}}">{{user.name}}</a>
      </div>
      <div class="divCell">{{user.username}}</div>
      <div class="divCell">{{user.email}}</div>
    </div>

  </div>
  <div ng-view>
<!-- Area of showing Views--!>
  </div>

</body>

</html>

Another thing to notice here is the href  attribute in anchor tag for user name.Now we have changed it to ‘#/users/{{user.id}}’.If you see our routing configuration this matches the below section.

when('/users/:userId',{
       templateUrl : 'userdetails.html',
       controller : 'DetailsController'
    }).

So clicking this hyperlink will render the ‘userdetails.html’ view within the div tags having ng-view  directive.

Creating View templates and Controllers

Everything is ready so lets create our two view templates and corresponding controllers.

userdetails.html & DetailsController.js

userdetails.html

<br>
<div class="details">

  <div><strong>User Name:</strong> {{userDetails.username}}</div>
  <div><strong>Phone:</strong> {{userDetails.phone}}</div>
  <div><strong>Website:</strong> {{userDetails.website}}</div>
  <h3>Address</h3>
  <div><strong>Street:</strong>{{userDetails.address.street}}</div>
  <div><strong>Suite:</strong>{{userDetails.address.suite}}</div>
  <div><strong>City:</strong>{{userDetails.address.city}}</div>
  <div><strong>Zip code:</strong>{{userDetails.address.zipcode}}</div>

  <div><a href="#/posts/{{userDetails.name}}/{{userDetails.id}}">Go to Posts >></a></div>
</div>

DetailsController.js

(function(){
var DetailsController = function($scope, $http,$routeParams) {

  console.log("DetailsController");

  var onDetailsSuccess = function(response) {
    console.log("onDetailsSuccess");
    $scope.userDetails = response.data;

  };

  var onDetailsError = function() {
    $scope.info = "Error retrieving Post data";
  };

  $http.get("http://jsonplaceholder.typicode.com/users/" + $routeParams.userId)
    .then(onDetailsSuccess, onDetailsError);

};

//Register controller with module
app.controller("DetailsController", DetailsController);
})();

 

Note that in details.html again we have a hyperlink “Go To Posts” which will display all posts of this particular user.Here href  is “#/posts/{{userDetails.name}}/{{userDetails.id}}” which will match the  third section in our routing configuration.

when('/posts/:userName/:userId',{
       templateUrl : 'posts.html',
       controller : 'PostController'
    })

So lets define this view and corresponding controller.

posts.html & PostController.js

posts.html

<h2>Posts by {{userName}}</h2>

<div ng-repeat="post in posts">
    <div class="details">
    <strong>{{post.title}}</strong>
    <p><em>{{post.body}}</em></p>
    </div>
    <br>
  </div>

PostController.js

(function(){
var PostController = function($scope, $http,$routeParams) {

  console.log("PostController");

  var onPostSuccess = function(response) {
    console.log("onPostSuccess");
    $scope.userName = $routeParams.userName;
    $scope.posts = response.data;

  };

  var onPostError = function() {
    $scope.info = "Error retrieving Post data";
  };

  $http.get("http://jsonplaceholder.typicode.com/posts/?userId=" + $routeParams.userId)
    .then(onPostSuccess, onPostError);

};

//Register controller with module
app.controller("PostController", PostController);
})();

For accessing the url parameters in your controller code we use another angular service called $routeParams. As you can see in the above example controller we access the username and user id as shown below.

$scope.userName = $routeParams.userName;
...

 $http.get("http://jsonplaceholder.typicode.com/posts/?userId=" + $routeParams.userId)
    .then(onPostSuccess, onPostError);

OK.This completes our sample.So lets run it…

Layout  View

image

Click on any Employee to bring  details view .

image

Click on ‘Go to Posts’ link to bring  posts view .

image

Also here is a link to excellent pluralsight course on getting started with Angular JS by Scott Allen.

Tagged on: , ,

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.