1

I'm having a single page application, but with different tabs. Only for one tab I want to show a google charts. I don't want to include and load the charts js file jsapi directly, but only if the specific tab is accessed.

Therefore I have to add the js as follows dynamically:

var script = document.createElement('script');
script.src = '//http://www.google.com/jsapi?ext.js';
document.body.appendChild(script);

Problem: how can I detect when the js has been completely loaded, so that I can continue as follows?

if (whenJspaiLoaded()) {
    google.load('visualization', '1', {packages: ['corechart']});
    google.setOnLoadCallback(drawChart); //my custom function
}
membersound
  • 81,582
  • 193
  • 585
  • 1,120

4 Answers4

2

Here is my implementation

    <style>
    .preloader {
        height:350px; background:url(images/719.gif) left no-repeat;
    }
    </style>
    <div id="columnchart_material"><div class="preloader">&nbsp;</div></div>
<script type="text/javascript"
          src="https://www.google.com/jsapi?autoload={
            'modules':[{
              'name':'visualization',
              'version':'1',
              'packages':['corechart']
            }]
          }">
</script>
    <script>
google.setOnLoadCallback(drawChart);

      function drawChart() {
    var chart = new google.visualization.LineChart(document.getElementById('columnchart_material'));
                options.title='English'
                options.series[1].lineWidth = 0;
            chart.draw(data,options );
}
    </script>

Codepen click here

Murali
  • 409
  • 11
  • 17
2

Give Angular Google Chart a try. It abstracts the chart management behind a directive so you just pass it an object with the data, options, and chart type and it does the rest. It doesn't add the script tag until the first time it loads the directive or you ask for the promise that returns when the library loads. If you really want to suppress library loading you're need to be sure the directive element isn't loaded in the background until you actually need it. So use ng-if instead of ng-show or put it in a different routed view.

nbering
  • 2,725
  • 1
  • 23
  • 31
  • While this might work, it's an additional dependency. Nobody knows how long it will be supported in future, so I don't want to rely on it. – membersound Apr 24 '16 at 14:08
  • 1
    Understandable, I haven't had as much time to work with it lately and it's only in the last week or so that other people have taken an interest in contributing maintenance pull requests where I haven't had time to write updates. I'm still here though, I always try to answer github issues and questions on gitter as quickly as possible. – nbering Apr 24 '16 at 14:30
  • Is there for your function to have a trigger when the library is loaded? How do you handle it internally @nbering – WJA Feb 06 '19 at 09:59
  • 1
    @JohnAndrews I have a blog post that explains that. https://nicholasbering.ca/angularjs/2015/04/02/google-charts-api-promise/ – nbering Feb 06 '19 at 11:31
0

As there seems to be no working solution on the net so far, I hope this will help someone in future. Key concept is to delay both the js file loading and the charts component initialization with a callback.

The service to load the js files:

app.service('gchart', ['$window', '$q', '$rootScope', function ($window, $q, $rootScope) {
      var deferred = $q.defer();

      //run when the jsapi is loaded
      $window.callback = function () {
            $window.google.load('visualization','1',{
                packages: ['corechart'],
                callback: function() {
                    //again having a callback to wait for the visualization to load
                    $rootScope.$apply(function() {
                        deferred.resolve();
                    });
                }
            });
      }

      // dynamically adding the js file on page access
      var script = document.createElement('script');
      script.src = '//www.google.com/jsapi?callback=callback';
      document.body.appendChild(script);

      return deferred.promise;
}]);

Usage as directive:

app.directive(.., ['gchart', function(.., gchart) {
   return {
      //...
      link: function(scope, elm, attr) {
          scope.init = function() {
              var viz = new google.visualization.arrayToDataTable(data);
              //add options, linechart, draw, whatever
          };

          // delay the creation until jsapi files loaded
          loadGoogleChartAPI.then(function () {
              scope.init();
          }, function () {
              //ignore
          });           
       }
   }
}
membersound
  • 81,582
  • 193
  • 585
  • 1,120
-1

Async function with callback:

function async(u, c) {
  var d = document, t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0];
  o.src = '//' + u;
  if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
  s.parentNode.insertBefore(o, s);
}

Usage:

async('www.google.com/jsapi?ext.js', function() {
    google.load('visualization', '1', {packages: ['corechart']});
    google.setOnLoadCallback(drawChart);
});

from : https://stackoverflow.com/a/12821561/3279156

Community
  • 1
  • 1
sreeramu
  • 1,213
  • 12
  • 19
  • is `addEventListener` browser independent? IE, Chrome, FF, Opera? – membersound Apr 21 '16 at 08:53
  • @membersound for IE you can check this, http://stackoverflow.com/a/6927800/3279156 more about compatibility check in : http://caniuse.com/#feat=addeventlistener – sreeramu Apr 21 '16 at 08:58