0

I'm using a deferred promise because I need the app to wait for the result of an asynchronous call. The function retrieves the correct data, but I can't seem to get that back to my controller.

Specifically, the line of code

data : multiBarChartData

is not getting the resolved data from

function multiBarChartData()

Here is the factory:

angular.module('hapDash.services', []).factory('DataService', function ($http, $q, SESSION_ID) {

    return {
        multiBarChart : {
            data : multiBarChartData
        }
    };

    function multiBarChartData() {
        var deferred = $q.defer();
        $http({
            method : 'GET',
            url : '/services/data/v37.0/analytics/reports/00OP0000000Q9iB',
            headers : {
                'Authorization' : 'Bearer ' + SESSION_ID
            }
        }).success(function (data) {
            var report02ChartData = [];
            angular.forEach(data.groupingsDown.groupings, function (de, di) {
                var report02Values = [];
                report02ChartData.push({'key' : de.label, 'values' : report02Values});
                angular.forEach(data.groupingsAcross.groupings, function (ae, ai) {
                    report02Values.push({'x' : ae.label, 'y' : data.factMap[de.key + '!' + ae.key].aggregates[0].value});
                });
            });
            data = report02ChartData;
            deferred.resolve(data);
        }).error(function () {
            deferred.reject('There was an error accessing the Analytics API')
        })
        return deferred.promise;
    }
});

... and here is the controller:

var app = angular.module('hapDash', ['config', 'nvd3', 'gridster', 'hapDash.services']);

app.controller('HapDashCtrl', function ($scope, $timeout, DataService) {

    $scope.dashboard = {
        widgets : [{
                col : 0,
                row : 0,
                sizeY : 1,
                sizeX : 1,
                name : "Multi Bar Chart",
                chart : {
                    data : DataService.multiBarChart.data(),
                    api : {}
                }
            }
        ]
    };

});

I'm trying to get the controller code

data : DataService.multiBarChart.data(),

to pull the async response once it is complete.

What am I doing wrong?

1
  • $http() itself returns a promise, there is no need to manually create another one. Commented Jun 18, 2016 at 13:11

2 Answers 2

0
DataService.multiBarChart.data()

returns a promise and not the real data. You can access the real data in the controller via:

DataService.multiBarChart.data().then(
  function(data) {
    /*do something with data*/
  }
).catch(
  function(err) {
    /*handle error*/
  }
);

Furthermore you're falling for a famous Promise anti-pattern here by not using the promise returned by the $http service and therefor breaking the promise chain. The following snippet wouldn't break the promise chain and would let you handle any error that might occur at a single catch block.

function multiBarChartData() {
  return $http(/*...*/).then(
    function (response) {
      var report02ChartData = [];
      .success(function (data) {
        var report02ChartData = [];
        angular.forEach(response.data.groupingsDown.groupings, function (de, di) {
            /*...*/
            });
        });
      data = report02ChartData;
      return data;
    });
}

This way the $http errors are also emitted in the .catch(fuction(err){..}) block in the controller, because you didn't break the chain.

UPDATE: Since .success/.error are not chainable and marked deprecated, you should use .then/.error instead.

Sign up to request clarification or add additional context in comments.

2 Comments

This almost gets me there ... I'm now able to return data as an object to the controller, and even create an array from the object. But no matter what I do I'm unable to get the code line data : DataService.multiBarChart.data(), to use the result as the array; the chart widget returns "no data".
You can either wait for initialization of the widget until the promise is resolved (initialize it within the .then function like dfsq suggested) or return an empty object in multiBarChartData(), which is a variable stored in DataService (e.g. {dataArray: []}). The dataArray then is filled in the .then function of the promise. Hope this helps...
0

You need to initialize $scope.dashboard object when promise is resolved:

app.controller('HapDashCtrl', function($scope, $timeout, DataService) {

    DataService.multiBarChart.data().then(function(data) {
        $scope.dashboard = {
            widgets: [{
                col: 0,
                row: 0,
                sizeY: 1,
                sizeX: 1,
                name: "Multi Bar Chart",
                chart: {
                    data: data,
                    api: {}
                }
            }]
        };
    });

});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.