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.
Here is overall structure. Red arrows show the controllers responsible for each section of the view. Green arrows show the message broadcasting.
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
- the default tab is set
- A dummy list of machines is created. In the real app this is fetched using ajax
- 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.
That was a cool explanation ..Andre
ReplyDeleteyou can find a similar one here too..
http://sharepoint-2010-world.blogspot.in/2013/10/broadcast-emit-and-on-in-angular-js.html