0

I am trying to return an object through the _fail callback (Yes, this is meant to run the fail callback), but failSeries is returning as undefined in the console. Any ideas?

var ChartModule = (function ( $, HC, HA, window, undefined) {

//Define public object
var pub = {};

//Private methods
var _getChartData = function (URL, sendData) {

    var xhrObject =  $.ajax({
                            url: URL,
                            type: "POST",
                            data: sendData,
                            success: function (result) { },
                            error: function (jqXHR, textStatus, errorThrown) {}
                        });

    _chartDataResponse(xhrObject);
};

var _done = function (data, textStatus, jqXHR) {
    var seriesObject = $.parseJSON(data);
    return seriesObject;
};

var _fail = function(){
    var failSeries = [];
    var seriesData = {
        data: [{y: 7, id: 'pointAssets', color: '#5c8fb8'}, {y:10, id: 'pointLiabilities', color: '#bb77b5'}, {y:-3, id: 'pointResult', color: '#cc5971'}],
    };
    failSeries.push(seriesData);

    return failSeries;
};

var _chartDataResponse = function(xhrObject){
    xhrObject.then(_done, _fail);
};

var _renderChart = function(renderTo, seriesObject){
    console.log("Chart will be rendered to: '" + renderTo + "'");
    console.log(seriesObject);
};

//Public methods
pub.getChartData = _getChartData;
pub.renderChart = _renderChart;

return pub;
})(jQuery, Highcharts, HighchartsAdapter, window, undefined);

I am then using my module in the following way in an attempt to view the object that has been returned by either the success or fail callabcks:

$(function(){
var x = ChartModule.getChartData("someURL", {test: "test"});
ChartModule.renderChart("breakdown-chart", x);

});

Tomuke
  • 869
  • 2
  • 8
  • 26

2 Answers2

0

I am trying to return an object through the _fail callback (Yes, this is meant to run the fail callback). I am then using my module in the following way in an attempt to view the object that has been returned by either the success or fail callabcks:

No. You can't do that. Callbacks don't return anything. See How do I return the response from an asynchronous call?.

but failSeries is returning as undefined in the console.

Because failSeries is a variable that is local to your _fail function, and gets returned to nothing from it.

Any ideas?

Return the promise. And then wait until it resolves before calling renderChart (from a callback).

var ChartModule = (function( $, HC, HA, window, undefined) {

    function getChartData(URL, sendData) {
        return $.ajax({
            url: URL,
            type: "POST",
            data: sendData
        }).then(done, fail);
    }

    function done(data, textStatus, jqXHR) {
        return $.parseJSON(data);
    }

    function fail() {
        // ignore errors, continue with fake data
        return new $.Deferred().resolve([
            {data: [{y: 7, id: 'pointAssets', color: '#5c8fb8'}, {y:10, id: 'pointLiabilities', color: '#bb77b5'}, {y:-3, id: 'pointResult', color: '#cc5971'}]}
        ]);
    }

    function renderChart(renderTo, seriesObject){
        console.log("Chart will be rendered to: '" + renderTo + "'");
        console.log(seriesObject);
    }

    return {
        getChartData: getChartData,
        renderChart: renderChart
    };

})(jQuery, Highcharts, HighchartsAdapter, window, undefined);

$(function(){
    ChartModule.getChartData("someURL", {test: "test"}).then(function(x) {
        ChartModule.renderChart("breakdown-chart", x);
    });
});
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 2
    Remember that jQuery's `.then()` doesn't automatically transmogrify rejected to fulfilled on return of a value - it just stays on the fail path and regards the returned value as the "reason". For this to handle errors properly, you would need to return `$.Deferred().resolve(...)` from `fail()` or include a fail handler in the eventual `.then()`. – Roamer-1888 Nov 13 '14 at 07:26
  • @Roamer-1888: Arghh, I always forget [how broken jQuery deferreds are](http://stackoverflow.com/a/23744774/1048572) :-/ Fixed. – Bergi Nov 13 '14 at 10:10
  • Yeah, they are indeed a tad different. – Roamer-1888 Nov 13 '14 at 10:55
0

With a slightly better understanding (and use) of $.ajax(), ChartModule will reduce down to far fewer public methods. In particular :

  • be aware that $ajax() returns a promise, which can (and should) itself be returned by getChartData() thus allowing consequential action on success/failure to be taken externally.
  • with appropriare low level error handling in a chained then() inside getChartData() you can make an error message AND the fake seriesData available where ChartModule.getChartData() is called.
var ChartModule = (function ( $, HC, HA, window, undefined) {
    //Private members
    var fakeSeriesData = { data: [{y: 7, id: 'pointAssets', color: '#5c8fb8'}, {y:10, id: 'pointLiabilities', color: '#bb77b5'}, {y:-3, id: 'pointResult', color: '#cc5971'}] };
    function _getChartData(URL, sendData) {
        return $.ajax({
            url: URL,
            type: "POST",
            data: sendData,
            dataType: 'json'
        }).then(null, function (jqXHR, textStatus, errorThrown) {
            var e = new Error(textStatus);
            e.seriesData = getFakeSeriesData();
            return e; //return an augmented Error object.
        });
    }
    function _renderChart(renderTo, seriesObject) {
        console.log("Chart will be rendered to: '" + renderTo + "'");
        console.dir(seriesObject);
        return ...;//something meaningful
    }
    function _getFakeSeriesData() {
        return $.extend({}, fakeSeriesData);
    }
    //Public methods
    return {
        getChartData: _getChartData,
        renderChart: _renderChart,
        getFakeSeriesData: _getFakeSeriesData//make the fake series data directly availalbe.
    };
})(jQuery, Highcharts, HighchartsAdapter, window, undefined);

This strategy will allow control to be execised where ChartModule.getChartData() is called, with no assumptions about what actions might be taken on success or failure of the AJAX other than, on error, to make the fake seriesData available with no knowledge of how/whether it will be used.

Call as follows :

$(function() {
    ChartModule.getChartData("someURL", {
        test: "test"
    }).done(function(seriesData) {
        ChartModule.renderChart("breakdown-chart", seriesData);
    }).fail(function(error) {
        if(error.seriesData) {
            console.log(error.message);
            ChartModule.renderChart("breakdown-chart", error.seriesData);
        } else {
            console.error(error);
            //some othe couse of action
        }
    });
});

At some other point in your code, you could call ChartModule.getChartData() and take completely different actions in response. You could, on error, even inject some other fake seriesData that is, for whatever reason, more appropriate than the default.

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44