Blog moved to http://www.andrevdm.com/

Monday 25 February 2013

Learning AngularJs

 

I recently had to build a simple HTML application and decided to use AngularJS. I’ve used KnockOut in the past and found it easy to use. AngularJS is a little more opinionated than KO so there is a bit more that needs to be done to get a basic app working. However it is still simple and easy to follow and the end result definitely justifies the tiny bit of extra work.

Where I did have a problem was in understanding how the change tracking works. In KnockOut it is very clear, observables do all of the work and observables are easy to understand. In AngularJS there are no observables and everything works like “magic”. This so far has been my biggest issue with AngularJS. I find it hard to simply follow a set of rules without any understanding of the reasoning behind them. When I started building a slightly more complicated application it refused to work correctly and I could not work out why with the “magic” explanation.

After a little bit of searching I was able to come up with an explanation of how it worked and based on that some guidelines for structuring my app. The end result was very impressive. The code was simple, I had separated concerns and everything just worked. Overall I’ll definitely be using AngularJS more.

 

Pushing back the magic

Firstly AngularJS uses dirty tracking rather than observables. It will periodically scan you scope variables to see if their values have changed from the previous scan and if they have it will then updated the UI and fire the change events. That is it, pretty simple actually.

The other thing that greatly simplified my application was to use broadcast messages rather than trying to share things across the $rootScope. This allowed me to have controllers that are completely separate. Interaction between the controllers is always event-based. This also avoids complexities that arise when you are going across scopes and having to check what phase angular is in

 

Example

As a simple example I’ll show how I structured a simple tabbed interface. As this is not a post about angular binding but rather about the JS structure I’ve just bound directly to JSON text

This is what the UI looks like. There are two buttons that represent the tab pages and an area for the tab content.

image

 

Here is overall structure. Red arrows show the controllers responsible for each section of the view. Green arrows show the message broadcasting.

 

image

 

The code for the HTML page is straightforward

<!doctype html>
<html ng-app="PerformanceApp">
<head>
<script src="angular.min.js"></script>
<script src="PerformanceApp.js"></script>
<script src="NodePerformanceCtrl.js"></script>
<script src="NodesCtrl.js"></script>

<link href="cluster.css" rel="stylesheet" type="text/css" />

<title>Cluster overview</title>
</head>
<body>
<div class="tabs">
<button ng-click="CurrentTab='Nodes'" ng-class="{'selTab': CurrentTab=='Nodes', 'unSelTab': CurrentTab!='Nodes'}">Nodes</button>
<button ng-click="CurrentTab='NodePerformance'" ng-class="{'selTab': CurrentTab=='NodePerformance', 'unSelTab': CurrentTab!='NodePerformance'}">Performance</button>
</div>

<div class="tab" ng-controller="NodesCtrl" ng-show="CurrentTab=='Nodes'">
<div class="tabHeader">Nodes</div>
<span class="tabBody">
<pre>{{Nodes|json}}</pre>
</span>
</div>

<div class="tab" ng-controller="NodePerformanceCtrl" ng-show="CurrentTab=='NodePerformance'">
<div class="tabHeader">Performance</div>
<span class="tabBody">
<pre>{{Performance|json}}</pre>
</span>
</div>

</body>
</html>


 



The “tab” buttons show or hide sections by setting the value of the CurrentTab scope variable. The “tabs” are just divs each with its own controller.



This is the application initialisation code



var app = angular.module('PerformanceApp', []);

app.run( function( $timeout, $http, $rootScope ){
$rootScope.CurrentTab = "Nodes";

var machines = [
{"Name": "m1", "IP": "127.0.0.1"},
{"Name": "m2", "IP": "127.0.0.2"}
];

$timeout(
function(){
$rootScope.$broadcast( 'machinesUpdated', machines );
},
500 );

} );


Again nice and simple. On app.run




  1. the default tab is set


  2. A dummy list of machines is created. In the real app this is fetched using ajax


  3. A broadcast message is schedule in 500ms



 



The controllers then respond to the broadcast and update their local scope variables



function NodePerformanceCtrl($scope,$http,$timeout) {
$scope.Performance = {};

$scope.$on( "machinesUpdated", function( event, args ){
for( var m in args ){
var machine = args[m];

$scope.Performance[machine.Name] = machine.IP;
}

} )
}


 



Though this is a trivial example it does show how AngularJS helps you layout your application. It should also illustrate how using $broadcast messages help keep your controllers separated.