Creating a Visualization App Using the Google Charts API and AngularJS – Part 2
The first part of this tutorial focused on the use of AngularJS controllers and the use of $scope
. This part of the tutorial will focus on Angular directives their relation to $scope
. We’ll start exactly from where we left off in the first article.
AngularJS Directives
Directives are another interesting and important aspect of AngularJS. Directives are custom tags or attributes, which enhance the abilities of HTML. For example, consider a simple input
element:
<input type="text" />
Now, suppose we wrote a directive for a datepicker and want to apply that to the above input element. We would apply it in the following fashion.
<input type="text" datepicker />
In the first tutorial, we collected our chart data, along with the chart options, and bound the data to a div
from the controller. However, directives provide a better and more organized way to accomplish the same thing. Before writing our own directive, let’s have a look at a directive which is already in the Angular seed project. Open up app/js/directives.js
and find the following code:
'use strict';
/* Directives */
angular.module('myApp.directives', []).
directive('appVersion', ['version', function(version) {
return function($scope, elm, attrs) {
elm.text(version);
};
}]);
This example defines a directive named appVersion
. Note that when we add this directive, whose name is written in CamelCase), as a custom tag to an element, the casing is converted to SnakeCase.
In this directive, we are assigning a version number to the element to which the directive is attached. But, where is this version number coming from? Well, we have something called an AngularJS service, and that is where the version comes from. Open up app/js/services.js
and you can see the version number defined there.
'use strict';
/* Services */
// In this case it is a simple value service.
angular.module('myApp.services', []).
value('version', '0.1');
In order to access the value of version
in the directive, it is injected into the directive using the following code:
directive('appVersion', ['version', function(version) {
Then, it is assigned to the element using elm.text(version);
.
Now, simply add a div
to index.html
, as shown below. This attaches the appVersion
directive to a span
element.
<div >Angular seed app: v<span app-version></span></div>
To run the application, issue the following command from a terminal window.
node scripts/web-server.js
Next, point your browser to http://localhost:8000/app/index.html
. The version defined in services.js
should be displayed on the page. Now, let’s create a new directive for displaying our chart.
Creating an AngularJS Directive
Let’s create a new directive named gChart
in directives.js
:
'use strict';
/* Directives */
angular.module('myApp.directives', []).
directive('appVersion', ['version',
function (version) {
return function ($scope, elm, attrs) {
elm.text(version);
};
}
])
.directive('gChart', function () {
return function ($scope, elm, attrs) {
};
});
In the previous article, we bound the data in the controller itself. This time we’re goint to pass the data using $scope
and bind it inside the directive. The modified code is shown below.
'use strict';
/* Directives */
angular.module('myApp.directives', []).
directive('appVersion', ['version',
function (version) {
return function ($scope, elm, attrs) {
elm.text(version);
};
}
])
.directive('gChart', function () {
return function ($scope, elm, attrs) {
var chart = new google.visualization.LineChart(document.getElementById('chartdiv'));
chart.draw($scope.chart.data, $scope.chart.options);
};
});
Inside controllers.js
, remove the last two lines where we bind data to a div
, and instead save the chart data and options inside $scope
. The file should now look like this:
'use strict';
/* Controllers */
google.load('visualization', '1', {packages:['corechart']});
google.setOnLoadCallback(function () {
angular.bootstrap(document.body, ['myApp']);
});
angular.module('myApp.controllers', []).
controller('MyCtrl1', ['$scope', function($scope) {
var data = google.visualization.arrayToDataTable([
['Year', 'Sales', 'Expenses'],
['2004', 1000, 400],
['2005', 1170, 460],
['2006', 660, 1120],
['2007', 1030, 540]
]);
var options = {
title: 'Company Performance'
};
var chart = {};
chart.data = data;
chart.options = options;
$scope.chart = chart;
}])
.controller('MyCtrl2', [function() {
}]);
Now, add the gChart
directive to the div
in index.html
as shown below:
<div ng-controller="MyCtrl1" id="chartdiv" g-chart></div>
Next, run the app and you should be able to see the graph.
At this point, we are using controllers to take care of the application logic. Data is assigned to the view via $scope
, and DOM manipulation is handled using the directive.
More Information on Directives
When creating a directive, we can specify how we want to use the directive. For example, a directive can be used as a class, an attribute, or a tag. In this tutorial, we’ll be using our directive as an attribute. Hence, we can explicitly declare that using restrict : A
. A minimalistic directive that uses this approach is shown below.
.directive('gChart', function() {
return {
restrict: 'A',
link: function($scope, elm, attrs) {
var chart = new google.visualization.LineChart(document.getElementById('chartdiv'));
chart.draw($scope.chart.data, $scope.chart.options);
}
};
});
We can also remove the hard coded chartDiv
from the directive code and access it using the elm
argument, as shown below.
.directive('gChart', function() {
return {
restrict: 'A',
link: function($scope, elm, attrs) {
var chart = new google.visualization.LineChart(elm[0]);
chart.draw($scope.chart.data, $scope.chart.options);
}
};
});
Conclusion
In this tutorial, we focused on the use of directives. In the next part of this tutorial, we will dig deeper into the two-way binding features of AngularJS, and incorporate them into our existing app. In the meantime, all of the code from this article is available on GitHub.