Introduction
In the recent times, we have been building web application using any web technology and when it comes to client side programming for these application, most of us used pure OOJS or Jquery to do some validation and to some extent communicating to the server using XMLHttpObject or $.ajax. Many frameworks provided server side MVC framworks that gave some excellent advantage on the server side in terms of separation of concerns, responsibility patterns which made the code more managable and clean.
With the evolution of some great framework in the javascript world like ExtJS, AngularJS, and others, we tried to bring those advantages that we had on server side to client side.
These frameworks are really great when building rich client side applications. These frameworks provided a very interesting way of building the client side application by leveraging the power of asynchronous calls. This they refered as SINGLE PAGE APPLICATIONS.
By SPA, I mean the the client asks the server for a full html page just once and that is the moment you type a url and hit enter in the browser, the server responsds with a html file which then has some javascript code that unwinds the client side MV* application that take care of rest of the stuff from navigation to server calls to rendering and so on.
The beauty of these frameworks is that now you have complete separation of concerns as we have have models to handle data, view to display the data and some componets called as controllers or view models to handle the actions.
I have been building SPA using angularJS for some time now and I really love tthe way angularJS simplifies the things of building such application and at the same time reduces the no of lines of code we have to write to built a certain functionality. This is the prime reason of chosing angularJS for this article.
You can find more about angularJS on their website. For beginners, you can find good videos at egghead portal
A brief introduction to AngularJS
I am going to give some brief introduction about some terms that I may be using in this article so that any one can just read this article without ferquent refering other sources.
AngularJs is an open source web application framework maintained by Google and community and assits developers in creating single page applications. Its goal is to augment web applications with model-view-controller (MVC) capability in an effort to make development and testing easier.
Main design goals
- De-couple DOM manipulation from core logic
- Test driven development
- De-couple client side and server side.This allows development work to progress in parallel, and allows for reuse of both sides.
- Guide developers through the entire journey of building an application: from designing the UI, through writing the business logic, to testing.
AngularJS uses the following terminologies
Module: A logical component that can be used to logically group components. This can act as the parameter to angular bootstrapping. This can be created as
var myApp=angular.module("MyAngularApp"[<comma separarated list of dependencies>]);
Controller: A javascript component that can listens to the actions that are performed on the html view and contains the javascript code containg the logic. This can be created as
angular.module("MyAngularApp").controller("UserCtrl",["$scope",function($scope)
{
}]);
Directive: A component in angularJS that is used for any DOM manipulation. In angular we cannot directly interact with DOM from any other component other than directives. We can create a directive as
angular.module("MyAngularApp").directive("userwidget",["$scope",function($scope)
{
return{
restict:'A',
link:function(scope,elem,attrs){
}
};
}]);
For further details on directives please refer to directives section on angularJS website
Services/Factories: Specific components that are generally used to define some singleton objects that are used to talk to the server to get and send JSON data from/to the server. They can be defined as
angular.module("MyAngularApp").factory("UserService",['$http',function($http)
{
var Service={};
Service.getUsers=function()
{
}
}]);
There are ways other ways to access resources on the server,one such way is using a $resources service present in angularJS. You must be thinking that why angularJS team introduced two things to do the same stuff of getting data from the server. Actually $resources service is more REST oriented which uses $http internally.
Providers: Providers lies in the core of angularJS framework. As per the angularJS documentation, "the Provider recipe is the core recipe type and all the other recipe types are just syntactic sugar on top of it. It is the most verbose recipe with the most abilities, but for most services it's overkill. Provider recipe is syntactically defined as a custom type that implements a $get
method. This method is a factory function just like the one we use in Factory recipe. In fact, if you define a Factory recipe, an empty Provider type with the $get
method set to your factory function is automatically created under the hood." For more about Providers, please visit angularJS website.
After the brief introduction of angularJS, let us focus now on our core topic.. To start with, we will discuss the overall structure of the application and its core compoments. Before diving into those, here is a typical folder structure of an enterprise class application. There are lots of other ways to structurize your code base, but I personally perfer this one, as this would make the code more maintainable.
/js
../MyApp ..../Module 1 ....../controllers ....../directives
....../partials ....../resources ....../less
....../filters
......app.js ..../Module 2
.
.
.
..../Module N
..../shared
....../commonHelpers ....../apis ....app.js place to do some application wide settings for $urlRouteProvider, $httpProvider etc
../MyAppTests
..../Unit
..../e2e
Once the application code structure is in place, let us discuss how main app.js should look like
angular.module("MyAppMasterModule",['Module 1',
'Module 2', ..................'Module N'])
.config(function($httpProvider)
{
headers in each call
}).run(function($rootScope, $state, $stateParams, $window)
{
bootstraped.
});
In the above code snippet, we can have any number of cofig blocks.
In a SPA, there is only one full fledged html page that is rendered by server, here is the typical such page
<html ng-app="MyAppMasterModule">
<head>
<title></title>
<link>
<!---load you css files here -->
</link>
<!-- load you JS library files here like angularJS, JQuery etc..
<!-- load you application specific JS files here. For a large enterprise class application, this section will typicalls have following files
MyApp-min.js or MyApp.js
MyApp-resouces.js
MyApp-templates.js
-->
</head>
<body>
<div>><!---The top header section and navbar</div>
<div ui-view><!--- the content section ---></div>
</body>
</html>
The above template is just an illustration on how the base page should look like. The attribute ui-view on the seconds div is angularJS directive that will be reponsible of including the template html into this section on execution.
For the sake of this article I am assuming that the developers are familar with some tools like Grunt, Bower, UglifyJS, html2Js and others which help create some files listed above. I will be writing some articles about these in near future.
Once this is done, the angularJS will take control of the things and looks for the definition of routes in the module level JS files or any router file present in the JS.
A typical module level JS file will look like.
angular.module("MyAppMasterModule.Module1",[<<comma separated dependency list>>])
.config(function ($stateProvider, $urlRouterProvider)
{
$stateProvider
.state('state1', {
abstract: true,
url: '/url1',
templateUrl: 'module 1/partials/statemain.html')
})
.state('state1.substate1', {
url: '/substate1',
templateUrl: 'module 1/partial/state1.html',
controller: 'Module1.state1Ctrl'
});
}
We can define many such states in this file and state could be even substates. To know more about ui-router, please refer to https://github.com/angular-ui/ui-router.
The templates or partials should be defined in their respective html files starting with html container tags like divs. The data binding can be done using angularJS templating framework.
Example, if we have a user service giving us the list of user with fields, name, age, username we can display the user list as shown in the following template
<div class="user-list">
<table>
<tr>
<th>Name</th>
<th>Age</th>
<th>User name</th>
</tr>
<tr ng-repeat="user in lstUsers">
<td>{{user.name}}</td>
<td>{{user.age}}</td>
<td>{{user.username}}</td>
</tr>
</table>
</div>
Conclusion
The articles achives its aim of giving the detailed first and initial steps of building an enterprise class Single Page Application using angularJS framework. In future as mentioned above I will be writing more articles about using javascript tools that makes developers life easier.
I will be dedicating one articles for writing unit tests of angularJS code as well.
I hope that you all will be benefitted by this article and I welcome any comments or suggestions.