Resolving multiple promises in routeprovider
Asked Answered
V

2

6

So I wanted to execute 2 http calls to get some groups and questions from my server and have both of these resolved in routeprovider so that the corresponding controller will not load before I have the relevant data.

In my other controllers I always worked with an initalData object to hold the data.

The resolve part:

resolve: {
                initialData: ["GroupsService" "QuestionsService", function (GroupsService, QuestionsService) {
                    return {
                     questions: QuestionsService.getAll(),
                     groups: GroupsService.getAll()
                }]
          }

When I tried to access the data in the controller using initialData.questions and initialData.groups respectively, I however received 2 promises instead of the data, even though the callback from the http got logged before the controller was instantiated.

QuestionsCtrl.$inect = ["DialogsService", "initialData", "QuestionsService"];

function QuestionsCtrl(DialogsService, questions, groups, QuestionsService) {
//Initialdata object which has 2 Promise properties
//This logs AFTER the callback in both http callbacks
console.log('controller initialized', initialData);

When I replaced the code with this (didn't use an initialData object, instead returned two other objects, it did work:

 resolve: {
                    questions: function (QuestionsService) {
                        //$http call for all questions
                        return QuestionsService.getAll();
                    },
                    groups: function (GroupsService) {
                        //$http call for all groups
                        return GroupsService.getAll();
                    }
                }

Does anyone have any logical explanation for why, in the first case I got back promises (despite that the data was actually present in the client), and the second one worked flawlessly?

Valerivaleria answered 15/2, 2015 at 14:33 Comment(0)
P
9

When you pass resolve to a route it calls $q.all on it implicitly for you. So when you return multiple values in resolve it waits for all of them to finish.

In your example - you just returned an object containing some values that are promises - you didn't wait for them so it got resolved immediately with the promises instead of unwrapping them.

You can of course explicitly wait for them too:

 initialData: ["a" "b","$q", function (a, b, $q) {
      return $q.all({
                     questions: a.getAll(),
                     groups: b.getAll()
             });
 }]
Polynesian answered 15/2, 2015 at 14:46 Comment(0)
E
3

If you wish resolve to wait, you need to return a promise, in your first case it's not a promise, rather it's just an object, it happens to have 2 objects that are however promises, but angular won't know that... If you wish to return it as a single resolve you can use:

return $q.all({ key1: promise, key2: promise }); 

and add $q as a dependency

Another thing, promises doesn't turn them self into raw values when data is received from the server, they stay promises, in the case of resolve, angular will dig out the resolved value and provide those instead of the promises. And again we need to go back to that angular needs to know it is dealing with promises.

Enki answered 15/2, 2015 at 14:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.