3
votes

This is a broad question so I will try to make it as narrow as possible. I have an ajax call method to load data from my server. The call works fine and gets the data. I have verified the data is available. This is done in the head of the web page. I have another method in the bottom of the page that draws a google column chart based on the data in the loaded in the ajax call. The problem is that the google charts method doesn't always have the data even though it is being loaded in the ajax call. Anyone seen this problem before? I have even went as far as to place a 2 second pause thinking that the google chart was just loading first, but it turns out that this is not the case. The caveat to this is that if I reload the page I get the data in the chart every time without fail.

Ajax call

var graphData = new Array();
var flag = false; 
var ajaxCall = function(){ 
    $.ajax({ 
        type: "GET",
        dataType: "json",
        url: "service/getGraphicalData",
        success: function(data) 
        {
            var indexNum = 0;
            $(data).each(function (index){
                var newDataArr = [data[index].date, data[index].hitCount,     data[index].leadCount];
                graphData[indexNum] = newDataArr;
                indexNum++;
                flag = true;
            });
            console.log("GData 1: " + graphData);
        }
    });  
};
ajaxCall(); <-- I make the call directly after the method declaration in the head of the page...

The google chart code.... setTimeout(google.load('visualization', '1', {packages: ['corechart', 'bar']} google.setOnLoadCallback(drawAnnotations))},2000); <-- put a two second pause on the calling of this method to see if it helped but no luck this is called at the foot of the page just before the tag

        function drawAnnotations() {
            console.log("GData 2: " + graphData);
             var chartData = new google.visualization.DataTable(); 
             chartData.addColumn('string', 'Day');
             chartData.addColumn('number', 'Hits');
             chartData.addColumn('number', 'Leads');

             /* chartData.addRows([
                    ["2015-03-17", 16, 14],
                    ["2015-03-17", 12, 10],
                    ["2015-03-17", 15, 13],
                    ["2015-03-17", 17, 14],
                    ["2015-03-17", 22, 21],
                ]); */
              chartData.addRows(graphData);
              var options = {
                title: 'Traffic Incoming Versus Leads Gained',
                annotations: {
                  alwaysOutside: true,
                  textStyle: {
                    fontSize: 14,
                    color: '#000',
                    auraColor: 'none'
                  }
                },
                hAxis: {
                  title: 'Date'                       
                },
                vAxis: {
                  title: 'Total Leads And Hits'
                },
                series: { 0: {color: '#d3d3d3'}, 1: {color: '#FF6600'} }
              };

              var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
              setTimeout(function(){chart.draw(chartData, options)},2000);
         }

Any help would be greatly appreciated... thanks

UPDATE

new src code:

var ajaxCall = function(){ 

    $.ajax({ 
        type: "GET",
        dataType: "json",
        url: "/service/getGraphicalData",
        success: function(data) 
        {
            var indexNum = 0;

            $(data).each(function (index){
                var newDataArr = [data[index].date, data[index].hitCount, data[index].leadCount];
                graphData[indexNum] = newDataArr;
                indexNum++;
                flag = true;
            });

            google.load('visualization', '1', {packages: ['corechart', 'bar']});
            drawAnnotations ( graphData );

            console.log("GData 1: " + graphData);
        }
    });  
};
ajaxCall();

Okay so I have updated my code to look like this, I am still calling ajax call but I keep getting a google.visualization.DataTable() is not a method after moving it into the success portion of the call, I feel like it is losing the available library for the src call but that doesn't make sense

I found this link here when trying to see if anyone else has had this problem, I made the modifications as he suggested to this

var ajaxCall = function(){ 
    google.load('visualization', '1', {packages: ['corechart', 'bar']});
    $.ajax({ 
        type: "GET",
        dataType: "json",
        url: "/service/getGraphicalData",
        success: function(data) 
        {
            var indexNum = 0;

            $(data).each(function (index){
                var newDataArr = [data[index].date, data[index].hitCount, data[index].leadCount];
                graphData[indexNum] = newDataArr;
                indexNum++;
                flag = true;
            });


            google.setOnLoadCallback(drawAnnotations ( graphData ));

            console.log("GData 1: " + graphData);
        }
    });  
};
ajaxCall();         

but then got the same error again... which results in the chart not loading. am I missing something,

GOT IT!!!!!

found a similar error here. Apparently the answer to this debacle is that the

google.setOnLoadCallback 

expects you to give it a function not call a function so the call to

 drawAnnotations( graphData ) 

needs to be wrapped in a

function() { drawAnnotations ( graphData ) } 

such as this

google.setOnLoadCallBack(function() { drawAnnotations ( graphData ) });

So the new methodology should look as such:

function drawAnnotations(graphInfo) {
    console.log("GData 2: " + graphData);
     var chartData = new google.visualization.DataTable(); 
     chartData.addColumn('string', 'Day');
     chartData.addColumn('number', 'Hits');
     chartData.addColumn('number', 'Leads');

      chartData.addRows(graphInfo);
      var options = {
        title: 'Traffic Incoming Versus Leads Gained',
        annotations: {
          alwaysOutside: true,
          textStyle: {
            fontSize: 14,
            color: '#000',
            auraColor: 'none'
          }
        },
        hAxis: {
          title: 'Date'                       
        },
        vAxis: {
          title: 'Total Leads And Hits'
        },
        series: { 0: {color: '#d3d3d3'}, 1: {color: '#FF6600'} }
      };

      var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
      setTimeout(function(){chart.draw(chartData, options)},2000);
 }
var graphData = new Array();
var flag = false; 
var ajaxCall = function(){ 
    google.load('visualization', '1', {packages: ['corechart', 'bar']});
    $.ajax({ 
        type: "GET",
        dataType: "json",
        url: "/service/getGraphicalData",
        success: function(data) 
        {
            var indexNum = 0;

            $(data).each(function (index){
                var newDataArr = [data[index].date, data[index].hitCount, data[index].leadCount];
                graphData[indexNum] = newDataArr;
                indexNum++;
                flag = true;
            });


            google.setOnLoadCallback(function(){drawAnnotations ( graphData );});

            console.log("GData 1: " + graphData);
        }

    });  
};
ajaxCall();
3

3 Answers

0
votes

Keep in mind the Ajax call isn't performed until after jQuery is being loaded.

One solution would be to run the chart code in the callback of the Ajax function, like so:

var ajaxCall = function(){ 
    $.ajax({ 
        type: "GET",
        dataType: "json",
        url: "service/getGraphicalData",
        success: function(data) 
        {
            var indexNum = 0;
            $(data).each(function (index){
                var newDataArr = [data[index].date, data[index].hitCount,     data[index].leadCount];
                graphData[indexNum] = newDataArr;
                indexNum++;
                flag = true;
            });
            drawAnnotations(); // Call the chart function here   
            console.log("GData 1: " + graphData);
        }
    });  
};

Better yet, I wouldn't expose the chart information as a global variable, and pass it as a parameter into the chartAnnotation function.

1
votes

what @Chandry said was absolutely right, I just can't upvote yet. One of the most confusing things about jQuery at first is how async works.

You don't want to do the 2000ms delay because it creates a race condition where your code will A - be slow, and B - not always work depending on network conditions.

Here's one of my examples:

    function setupDashboard()
    {
//get data from openweathermap Api
    $.getJSON('http://api.openweathermap.org/data/2.5/forecast?q=' +
      city + ',us&appid=' + apiKey + '&units=' + units)
        .fail ( () => {
          //TODO: implement failure logic
        })
        .success( (res, sts) => {
console.log(sts);

//call my methods to draw dashboard components
      drawWeatherIcon(res.list[0].weather[0].main);
      drawLineGraph();
      drawPieChart(res.list[0].clouds.all);
  }
});

Note that the page will load, and then slightly after, as soon as it receives the data successfully, it will draw the graphs.

0
votes

found a similar error here. Apparently the answer to this debacle is that the google.setOnLoadCallback expects you to give it a function not call a function so the call to drawAnnotations( graphData ) needs to be wrapped in a function() { drawAnnotations ( graphData ) } such as this google.setOnLoadCallBack(function() { drawAnnotations ( graphData ) });

so the methodology should look as such:

function drawAnnotations(graphInfo) {
    console.log("GData 2: " + graphData);
     var chartData = new google.visualization.DataTable(); 
     chartData.addColumn('string', 'Day');
     chartData.addColumn('number', 'Hits');
     chartData.addColumn('number', 'Leads');

      chartData.addRows(graphInfo);
      var options = {
        title: 'Traffic Incoming Versus Leads Gained',
        annotations: {
          alwaysOutside: true,
          textStyle: {
            fontSize: 14,
            color: '#000',
            auraColor: 'none'
          }
        },
        hAxis: {
          title: 'Date'                       
        },
        vAxis: {
          title: 'Total Leads And Hits'
        },
        series: { 0: {color: '#d3d3d3'}, 1: {color: '#FF6600'} }
      };

      var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
      setTimeout(function(){chart.draw(chartData, options)},2000);
 }
var graphData = new Array();
var flag = false; 
var ajaxCall = function(){ 
    google.load('visualization', '1', {packages: ['corechart', 'bar']});
    $.ajax({ 
        type: "GET",
        dataType: "json",
        url: "/service/getGraphicalData",
        success: function(data) 
        {
            var indexNum = 0;

            $(data).each(function (index){
                var newDataArr = [data[index].date, data[index].hitCount, data[index].leadCount];
                graphData[indexNum] = newDataArr;
                indexNum++;
                flag = true;
            });


            google.setOnLoadCallback(function(){drawAnnotations ( graphData );});

            console.log("GData 1: " + graphData);
        }

    });  
};
ajaxCall();