Creating a Visualization App Using the Google Charts API and AngularJS – Part 3

Jay Raj
Share

In the first and second parts of this series, we focused on AngularJS controllers and directives. In this part, we’ll focus on the two-way data binding feature of AngularJS.

Data Binding in AngularJS

Angular’s data binding allows changes to a model to be automatically reflected in the view, and vice versa. A detailed explanation of AngularJS data binding can be found here.

We will be adding a few features to our visualization app. First, we’ll add a drop down where we can select the type of graph. Let’s add a few charts in the drop down. Open up index.html and add a select element as shown below:

<select id="chartType"></select>

If we want, we can define the options for the dropdown in HTML only, but let’s do it the Angular way. Open up controllers.js, and define the options as shown below.

$scope.chartTypes = [
  {typeName: 'PieChart', typeValue: 'PieChart'},
  {typeName: 'BarChart', typeValue: 'BarChart'},
  {typeName: 'ScatterChart', typeValue: 'ScatterChart'},
  {typeName: 'LineChart', typeValue: 'LineChart'}
];
$scope.chartType = $scope.chartTypes[0];

Now, controllers.js looks 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.chartTypes = [
      {typeName: 'LineChart', typeValue: '1'},
      {typeName: 'BarChart', typeValue: '2'},
      {typeName: 'ColumnChart', typeValue: '3'},
      {typeName: 'PieChart', typeValue: '4'}
    ];
    $scope.chartType = $scope.chartTypes[0];
    $scope.chart = chart;
  }])
  .controller('MyCtrl2', [function() {
  }]);

Now, we need to bind chartTypes to the drop down. In AngularJS, we can bind options to a drop down using ngOptions. We also need to bind chartType to the selected value in the drop down, and for that we use ngModel. So, add attributes named ng-options and ng-model to the drop down, as shown below.

<select id="chartType" ng-model="chartType" ng-options="c.typeName for c in chartTypes">
</select>

ng-options iterates over the values in chartTypes and binds each typeName to the drop down. Before running the node server, we need to modify the ng-controller value such that it is attached to the body element. The resulting index.html file is shown below.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>My AngularJS App</title>
    <link rel="stylesheet" href="css/app.css" />
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
  </head>
  <body ng-controller="MyCtrl1">
    <div g-chart></div>
    <select id="chartType" ng-model="chartType" ng-options="c.typeName for c in chartTypes">
    </select>
    <div>Angular seed app: v<span app-version></span></div>

    <script src="lib/angular/angular.js"></script>
    <script src="lib/angular/angular-route.js"></script>
    <script src="js/app.js"></script>
    <script src="js/services.js"></script>
    <script src="js/controllers.js"></script>
    <script src="js/filters.js"></script>
    <script src="js/directives.js"></script>
  </body>
</html>

Next, start the node server using the following command.

node scripts/web-server.js

By navigating to http://localhost:8000/app/index.html you should see the pre-populated drop down list.

Changing the Chart Type

We’re going to use ngChange to render our chart based on the section in the drop down list. Inside controllers.js define another $scope variable as shown below.

$scope.selectType = function(type) {
  $scope.chart.type = type.typeValue;
}

We also want to set the default chart type:

chart.type = $scope.chartTypes[0].typeValue;

After adding ng-change to the select element, it should look like this:

<select id="chartType" ng-change="selectType(chartType)" ng-model="chartType" ng-options="c.typeName for c in chartTypes">
</select>

Changing the chart type causes the $scope.chart.type variable to be udpated. This change should be watched so that the chart changes accordingly. For that we have some thing called $scope.$watch, which watches for a change in the $scope. In directives.js, wrap the link callback, inside $scope.$watch as shown below.

link: function($scope, elm, attrs) {
  $scope.$watch('chart', function() {
    var chart = new google.visualization.LineChart(elm[0]);

    chart.draw($scope.chart.data, $scope.chart.options);
  }, true);
}

This change causes every change to $scope.chart to trigger the callback function. Inside the $scope.$watch callback function, we need to check for $scope.chart.type and create a chart object accordingly. Modify the gChart directive in directives.js as shown below.

.directive('gChart',function() {
  return {
    restrict: 'A',
    link: function($scope, elm, attrs) {
      $scope.$watch('chart', function() {
        var type = $scope.chart.type;
        var chart = '';

        if (type == '1') {
          chart = new google.visualization.LineChart(elm[0]);
        } else if (type == '2') {
          chart = new google.visualization.BarChart(elm[0]);
        } else if (type == '3') {
          chart = new google.visualization.ColumnChart(elm[0]);
        } else if (type == '4') {
          chart = new google.visualization.PieChart(elm[0]);
        }

        chart.draw($scope.chart.data, $scope.chart.options);
      },true);
    }
  };
});

Now, when you select a different chart type from the drop down, the chart is updated.

Conclusion

In this tutorial, we implemented a drop down list and bound it using Angular’s two-way data binding. In our next tutorial, we’ll focus on adding some more features and bootstrapping the app to give it a feel good look. In the meantime, the code is available on GitHub, and a live demo is hosted on Heroku.