3

I would like to implement promises in my AngularJS application like you can see in this example: https://stackoverflow.com/a/12360882/371273

My application will take multiple arrays of data making multiple database hits on my server, but I have configured my server to return all of that data as one response in the idea of minimizing requests to keep my application as efficient as possible (the data is essentially useless unless all of the data gets to the client). So instead of doing this...

MyCtrl.resolve = {
    projects : function($q, $http) {
        return $http.get('/api/projects'});
    },
    clients : function($q, $http) {
        return $http.get('/api/clients'});
    }
};

I would like to be able to make a single $http GET request to a URL like /api/allData, and then have a promise for projects that will be set equal to allData.projects and a promise for clients that will be set equal to allData.clients, etc. (where allData is the data that came back with my single request). I'm still very new to promises, can someone give me an example of how I would set up these promises inside MyCtrl.resolve?

Community
  • 1
  • 1
winduptoy
  • 5,366
  • 11
  • 49
  • 67
  • You can't return multiple promises from $http, and I'm not sure why you'd want to. If the data must be used together, why wouldn't you be fine with the single promise? Can you provide a little more context? – Josh David Miller Jan 11 '13 at 08:06
  • 1
    Just return one promise that will have properites like 'projects', 'clients' and so on. Then your service should call allData and resolve the defer with the composite object (with clients and projects). Btw, isn't just enough to make the server to return all results in one object... then you wouldn't have to do any kind of additional work with promises. – matys84pl Jan 11 '13 at 08:32

2 Answers2

6

I believe that's what you are looking for:

var myApp = angular.module('myApp', []);

myApp.factory('myService', function ($http, $q) {
    return {
        getAllData: function () {
            return $q.all([ 
                // $q will keep the list of promises in a array
                $http.get('/api/projects'),
                $http.get('/api/clients')
            ]).then(function (results) {
            // once all the promises are completed .then() will be executed 
            // and results will have the object that contains the data 
                var aggregatedData = [];
                angular.forEach(results, function (result) {
                    aggregatedData = aggregatedData.concat(result.data);
                });
                 return aggregatedData;
            });
        }
     };
 });

The you can get your data from the final aggregatedData array (e.g.:aggregatedData[0], aggregatedData[1],...)

You can set up these promises inside MyCtrl.resolve in a single call:

resolve = {
    getAllData : myService.getAllData()
}
Denison Luz
  • 3,575
  • 23
  • 25
4

Well, there is not much of a point in using two promises that you know represent the same promise. But you could indeed create a service that receive handles the one promise and return two. Something like this:

var mod = angular.module('mod', []);
mod.service('theService', function($q, $http) {
  return function() {
    var cliDeferred = $q.defer(),
        proDeferred = $q.defer();

    $http.doYourStuff().then(function _onSuccess(data) {
      cliDeferred.resolve(data.clients);
      proDeferred.resolve(data.projects);
    }, function _onError(err) {
      cliDeferred.reject(err);
      proDeferred.reject(err);
    });

    return {clients: cliDeffered.promise, projects: proDeferred.promise};
  };
});

But as I said, there is not much of a point in this. Maybe a better solution, considering your service will return an array, would be return an object with empty arrays and fill them when the $http promise gets completed.

Caio Cunha
  • 23,326
  • 6
  • 78
  • 74
  • The example was great, thanks. However, this leads me to something else. Say I have a promise that will be resolved into an array. If I try to traverse that array with a for loop, I will get the error that `array[i] is undefined`. How can I check to see if the promise has been resolved before I try to access `array[i]`? – winduptoy Jan 13 '13 at 16:12
  • If you're just using a ng-repeat, you can point directly to your array `ng-repeat="row in myArray"`, if you need the contents of the array, you can [$watch](http://docs.angularjs.org/api/ng.$rootScope.Scope#$watch) it for changes. – Caio Cunha Jan 14 '13 at 08:38