javascriptcssjsonajaxjustgage

JavaScripts not recognizing var holding parsed JSON


I'm trying to code some gauges for an index page for various R/Shiny dashboards our company uses. The page is just a series of divs with some styling on them that lead to those various R apps.

Recently our execs expressed a lot of interest in seeing fuel-gauge style graphs on the top of the page signifying $income and $goals for the month for each division.

I decided to use the JustGage plugin to make the Gauges. We're getting the data out of csv's using a script my supervisor is throwing together to dump that data into JSON docs on the server. We're talking a JSON file with 6 lines. Very simple.

I'm using an AJAX XMLHttpRequest, and that seems to have worked. However, whenI go to store the parsed data into a variable and then reference it in my Gauge parameters, I get:

(index):182 Uncaught ReferenceError: feeData is not defined at (index):182 (anonymous) @ (index):182

in the inspect window.

That particular line is the first reference to that var containing the JSON data.

Any help would be...well, helpful!

< script >
  var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
  var feeData = JSON.parse(this.responseText);
  if (this.readyState == 4 && this.status == 200) {
    var feeData = JSON.parse(this.responseText);
  }
};
xhttp.open("GET", "test.json", true);
xhttp.send();
var g = new JustGage({
  titleFontColor: "black",
  labelFontColor: "black",
  id: "DEF",
  value: feeData.DEFCurrent,
  pointer: true,
  min: 0,
  max: feeData.DEFGoal,
  title: "DEF"
});
var g = new JustGage({
  titleFontColor: "black",
  labelFontColor: "black",
  id: "EBO",
  value: feeData.EBOCurrent,
  pointer: true,
  min: 0,
  max: feeData.EBOGoal,
  title: "EBO"
});
var g = new JustGage({
  titleFontColor: "black",
  labelFontColor: "black",
  id: "Company",
  value: (feeData.EBOCurrent + feeData.DEFCurrent),
  pointer: true,
  min: 0,
  max: (feeData.EBOGoal + feeData.DEFGoal),
  title: "Company"
});
var g = new JustGage({
  titleFontColor: "black",
  labelFontColor: "black",
  id: "Legal",
  value: feeData.LegalCurrent,
  pointer: true,
  min: 0,
  max: feeData.LegalGoal,
  title: "Legal"
}); 
</script>

Here's the JSON file

{"EBOGoal":1000,"EBOCurrent":900,"DEFGoal":2000,"DEFCurrent":1500,"LegalGoal":500,"LegalCurrent":450}

It may also be worth mentioning that the Gauges themselves work perfectly fine when I swap in dummy numeric values for the MAX and VALUE parameters of the js code for the Gauges.


Solution

  • You have a variable declaration issue, as well as a timing issue. Even if you fix the problem by moving the variable out of the onreadystatechange function scope, your code will be broken because the data is populated asynchronously and the rest of your code is processed synchronously. I suggest you either move your JustGage initialization into a function and call that function when your feeData is available:

    xhttp.onreadystatechange = function() {
      var feeData = JSON.parse(this.responseText);
      if (this.readyState == 4 && this.status == 200) {
        // call your function with the data
        setupJustGage(JSON.parse(this.responseText));
      }
    };
    
    function setupJustGage(feeData) {
        ...
        var g = new JustGage({
          titleFontColor: "black",
          labelFontColor: "black",
          id: "DEF",
          value: feeData.DEFCurrent,
          pointer: true,
          min: 0,
          max: feeData.DEFGoal,
          title: "DEF"
        });
        var g = new JustGage({
          titleFontColor: "black",
          labelFontColor: "black",
          id: "EBO",
          value: feeData.EBOCurrent,
          pointer: true,
          min: 0,
          max: feeData.EBOGoal,
          title: "EBO"
        });
        ...
    }
    

    You could also wrap your XHR request in a function that returns a Promise and run the rest of your setup code in the then:

    function getData() {
        return new Promise(function(resolve) {
            var xhttp = new XMLHttpRequest();
            xhttp.onreadystatechange = function() {
              var feeData = JSON.parse(this.responseText);
              if (this.readyState == 4 && this.status == 200) {
                resolve(JSON.parse(this.responseText));
              }
            };
            xhttp.open("GET", "test.json", true);
            xhttp.send();
        })
    }
    
    getData().then(function(feeData) {
       var g = ...
    })