Search code examples
d3.jsrequirejsamd

Returning results of d3 request from amd module / requirejs


I'm trying to create a amd module that runs a d3 request (d3.json() in this case) and returns the data from the request. I can't seem to figure out how to make the module wait for the request to finish before it returns the data. As a result I keep getting undefined in my main program when I try to access the data.

define(['app/args'], function(args){

  d3.json("resources/waterData.php?stn=" + args.stationID, function (error, data) {

    var dataToReturn = {};

    //Do some stuff with data

    return dataToReturn;
  });

});

That is the basic structure of what I'm trying to do. I think the main issue is that the 2nd argument in d3.json is a callback for when the data is loaded, so when I try to return the data, it isn't getting outside the module. I haven't been able to figure out how to get the data from the callback to return it outside the module.


Solution

  • The real issue is that the d3.json function is asynchronous, so you can't just return the processed data from the outside function directly. One way you can work around this is by returning a promise rather than the data itself. You can use the d3.json callback to resolve the promise, and then other modules which depend on the data can register their own callbacks which will run once that promise has been resolved.

    For example, if you use jQuery's $.Deferred() you can do the following:

    define(['app/args', 'jquery'], function(args, $){
    
      // CREATE DEFERRED OBJECT
      var deferred = $.Deferred();
    
      d3.json("resources/waterData.php?stn=" + args.stationID, function (error, data) {
    
        var dataToReturn = {};
    
        //Do some stuff with data
    
        // RESOLVE NOW THAT THE DATA IS READY
        deferred.resolve(dataToReturn);
      });
    
      // RETURN THE PROMISE
      return deferred.promise();
    
    });
    

    Then when you want to use the data, you can require the above module, and register a listener that will fire once the data is ready:

    require(['nameOfYourModuleAbove'], function(deferred) {
    
      deferred.done(function(data) {
        // DO SOMETHING WITH YOUR DATA
      });
    
    })