0

I have a piece of source code like this

var projectPromises = $http.get('http://myapi.com/api/v3/projects?private_token=abcde123456');

  $q.all([projectPromises]).then(function(data) {
    console.log(data);
    return data[0];
  }).then(function(projects) {
    var data = projects.data;
    var promises = [];
    var file = [];
    for(var i = 0; i < data.length; i++){
       var url = 'http://myapi.com/api/v3/projects/' + data[i].id + "/owner";
       promises.push($http.get(url));

    }

    console.log(promises);
    $q.all(promises).then(function(user) {
      console.log(user);
    }, function(error) {
      console.log("error here");
      console.log(error);
    });

Let me explain my source code.

First, I have the first API which will return a list of projects and I assign to projectPromises. After I get the list of projects , each project will contain a project ID . I will loop over the projects list and fire the corresponding http request to get the owner of a project.

After that , I use Angular q module to defer the list of promises and log the list into the console

console.log(user);

It does not log anything here . I try to print the error and I know the reason is that not all projects contain the users list. If not , it will return 404 , and 200 for vice versa. So the promises list will contain both 200 and 404 object return from the API , so I guest that when use q to defer the promises , it throw the error if the object is 404. But I don't know how to fix this.

My final purpose is to get the owner for each project and they will be populated into an array.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
xtiger
  • 1,446
  • 2
  • 15
  • 33

2 Answers2

1

There's no need to use $q.all() unless you have multiple promises. $http.get() returns a promise, so you can just call .then on that promise.

Once you have the list of project IDs, you can map that to a set of promises that each have a .catch() to provide a fallback value if their respective request fails.

Once you have that, you can use $q.all() on the array of promises, then one more .then() and you should be all set.

var pProjects = $http.get('http://myapi.com/api/v3/projects?private_token=abcde123456');

pProjects
    .then(function (result) {
        // map the project IDs to an array of promises for each project's owner
        var pProjectOwners = result.data.map(function (proj) {
            return $http
               .get('http://myapi.com/api/v3/projects/' + proj.id + '/owner')
               .then(function (result) { return result.data; })
               // fallback value to use when a request fails
               .catch(function () { return 'no owner'; });
        });

        return $q.all(pProjectOwners);
    })
    .then(function (projectOwners) {
        console.log(projectOwners);
    })
    .catch(function (error) {
        console.error("something went wrong", error);
    });

And here's an alternate version with some refactoring to separate out the operation to get a project's owner:

function getProjectOwner(projectId) {
    return $http
       .get('http://myapi.com/api/v3/projects/' + projectId + '/owner')
       .then(function (result) { return result.data; })
}

var pProjects = $http.get('http://myapi.com/api/v3/projects?private_token=abcde123456');

pProjects
    .then(function (result) {
        // map the project IDs to an array of promises for each project's owner
        var pProjectOwners = result.data.map(function (proj) {
            return getProjectOwner(proj.id)
               // fallback value to use when a request fails
               .catch(function () { return 'no owner'; });
        });

        return $q.all(pProjectOwners);
    })
    .then(function (projectOwners) {
        console.log(projectOwners);
    })
    .catch(function (error) {
        console.error("something went wrong", error);
    });
JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • @charlietfl Glad to help. Remember that `.then()` and `.catch()` both create new promises. They don't have an effect on promises further upstream. – JLRishe Feb 29 '16 at 18:20
  • yup.. created a [plunker](http://plnkr.co/edit/1pecB8iq8uaN8SvMljme?p=preview) to see this for myself better – charlietfl Feb 29 '16 at 18:21
0

You're making your promises overly complicated. You can bind directly to your http call to interact with the promise $http returns.

$http.get("http://myapi.com/api/v3/projects?private_token=abcde123456").then(function (results) {
   // projects will be your array of projects
   var projects = results.data;

   // Use native Array for each to get reference to every object in array
   projects.forEach(function (project) {
     $http.get("http://myapi.com/api/v3/projects/' + project.id + "/owner").then(function (results) {
       var data = results.data;
       console.log(data); // This will log your owner
     });
   })
});

You should probably just nest your owner with the returned project json to limit these extraneous http requests, but that's a matter of server side architecture.

Kyle Alwyn
  • 71
  • 2
  • This doesn't do the same thing. It doesn't allow for all requests to be completed before proceeding – charlietfl Feb 29 '16 at 17:41
  • @charlietfl : agree, this does not answer my question . I want all of the task to get the project owner to run asynchronously and then when ready , I get the full list of owner. – xtiger Feb 29 '16 at 18:12
  • Sorry, did not see that constraint anywhere in the question. My answer answers the original question based on the wording. – Kyle Alwyn Mar 01 '16 at 03:57