Come far convivere diversi grafici Google Charts nello stesso controller AngularJS

Premetto che la soluzione proposta nel presente articolo non rappresenta la migliore soluzione, ma vuole essere un aiuto a quanti abbiano incontrato lo stesso problema dovendo implementare la stessa funzionalità.

Analizziamo il problema. Avevo la necessità di visualizzare più grafici, nello specifico, una versione tabellare e due grafici diversi sulla stessa pagina della mia pagina HTML gestita da un unico controller AngularJS.

L’applicazione fa uso del modulo ngRoute per gestire il routing delle pagine, anche se nell’esempio la pagina è unica, ma accessibile in due diversi endpoint root “/” e  “google-charts”, inseriti come link nell’header della pagina.


'use strict';

angular.module('myApp', ['ngRoute','ui.bootstrap','app.controllers', 'app.services'])
.config(['$routeProvider', function($routeProvider) {
     $routeProvider.when('/', {
            templateUrl : 'partials/google-charts.html',
            controller : 'mainController'});
     $routeProvider.when('/google-charts', {
            templateUrl : 'partials/google-charts.html',
            controller : 'mainController'});
     $routeProvider.otherwise({redirectTo: '/'});
}]);

L’esigenza di utilizzare una stessa “fonte dati” è stata gestita creando un servizio che mettesse a disposizione le opzioni ed i dati necessari ai grafici attraverso delle funzioni:

/* Services */

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

...

appServices.service('chartService', function(){
    
  
  var chartOptions = {
        title: "Graph Title",
        is3D: false,
        isStacked : true,
        fill : 20,
        displayExactValues : true,
        horizontalTitle: "Date",
        vertical: {
            title: "Vertical Title", 
            gridlines: {"count": 10}
        }
    };
   ...
   this.getChartOptions = function(){
        return chartOptions;
    }
   ...
}

Tale servizio viene poi utilizzato nel mainController che ci permette di gestire la pagina google-charts.html, definendo un semplice array di grafici i cui elementi differiscono solo per la tipologia di grafico da renderizzare.


/* Controllers */
var ctrl= angular.module('app.controllers', ['ui.bootstrap', 'googlechart']);

// create the controller and inject Angular's $scope

ctrl.controller('mainController', function($scope, chartService, userService) {
$scope.graphs = [];

...

$scope.chartSelectionChange = function (type) {
if(type != $scope.chart.type) {
$scope.currentChart = angular.copy($scope.chart);
$scope.currentChart.type = type;
$scope.chart.type = type;

....

$scope.graphs.push($scope.currentChart);

....

Come si può vedere definiamo una variabile nello scope che conterrà i nostri grafici e una funzione che prende come parametro il tipo di grafico da creare e che ci permette, dopo aver controllato che la tipologia di grafico sia diversa, do aggiungere un elemento all’array con il type giusto.
Nella pagina HTML, infine, possiamo definire i vari charts nel classico modo definito nella direttiva utilizzata, ma con una semplice modifica. ovvero utilizzando l’elemento “n” del nostro array per il rendering:

<div class="col-md-3" ng-controller="mainController">
...
    <div class="container-fluid" >
        
        <div class="row-fluid">
            <div class=".col-xs-12 .col-sm-6 .col-lg-8">
                <div id="chart1" google-chart chart="graphs[0]" style="{{cssStyle}}" on-ready="chartReady()" ng-init="chartSelectionChange('Table')"></div>
            </div>
        </div>
        <div class="row-fluid">
            <div class=".col-xs-12 .col-sm-6 .col-lg-8">
                <div id="chart2" google-chart chart="graphs[1]" style="{{cssStyle}}" on-ready="chartReady()" ng-init="chartSelectionChange('PieChart')"></div>
            </div>
        </div> 
        <div class="row-fluid">
            <div class=".col-xs-12 .col-sm-6 .col-lg-8">
                <div id="chart3" google-chart chart="graphs[2]" style="{{cssStyle}}" on-ready="chartReady()" ng-init="chartSelectionChange('ColumnChart')"></div>
            </div>
        </div>           
    </div>
...

Concludo dicendo che sicuramente che ci sono altri modi, anche più eleganti e puliti per fare la stessa cosa, ma la soluzione presentata fornisce un buon punto d’inizio per ottenere il risultato voluto.

Trovate l’intero codice su gitHub ed il codice funzionante su jsFiddle

Enjoy!

RSS AngularJob

ddelfio Written by: