Using json data outside the original JavaScript function

I’ve been working on a Reckoner that helps people calculate some figures. I started by hard coding some threshold figures into the JavaScript while I worked on most of the functionality. However, once that was done, I needed to modify the JavaScript so that it would pull the figures from the server. That way, I could store and modify the numbers via the back-end Rails app.

It was trivial to set up a Setting model and matching controller, and then have it pass a setting value in json. The json looked something like this:

{ setting_value: 123 }

I wanted to create a function called getSetting that would allow me to pass in the name of the setting, and have it return the matching value. I could then use it like this:

  function minSavings() {
    var minThreashold = getSetting('lower_savings_threshold');
    return minThreashold * coupleFactor();
  }

I was going to use jQuery getJSON, but I couldn’t get it to work. After a lot of head scratching this is what I ended up with.

  function getSettingFromServer(name) {
    var json = $.ajax({
      type: "GET",
      url: '/settings/' + name + '.json',
      async: false,  // This is the critical line!
      dataType: 'json',

      success: function () {
        console.log('Successfully retrieved ' + name);
      },
      error: function () {
        console.log('Error retrieving ' + name);
      }
    }).responseText;

    var data = $.parseJSON(json);
    return data.setting_value;
  }

  var cachedSettings = {};

  function getSetting(name) {
    if (typeof cachedSettings[name] === "undefined") {
      cachedSettings[name] = getSettingFromServer(name);
    }
    return cachedSettings[name];
  }

The problem was that standard JQuery ajax calls are asynchronous, and that means that the function tries to return a value without waiting for the ajax call to complete. The result being that nothing is returned. To correct this you have to prevent the ajax call being asynchronous. To do that I used a JQuery.ajax call as that gave me that option (async: false).

To ensure I didn’t repeatedly have to wait for the ajax call, I split the function into two to make it easier to cache the result. With that in place the setting was only called once, in spite of the fact that it was needed in a number of places.

This entry was posted in JavaScript, Ruby. Bookmark the permalink.