Nested promises in ui-router resolve

2.2k views Asked by At

I would like to get some data before the view shows, (resolve). But some of the data is dependent on the result of another promise. I get the job id (index) from $stateParams and look up the data in my service. Once completed, from this result (the job) I look up the settings and floors (each from a different service). Both return a promise.

I've came up with:

jobinfo: function(Jobs, Floor, JobSetting, $stateParams, $q) {

    var defer = $q.defer();

        Jobs.getByIndex($stateParams.index)
        .then(function(job) {
            console.log('got jobs');
            $q.all({floors: Floor.getByJob(job), settings: JobSetting.getByJob(job)})
            .then(function(info) {
                console.log('got info');
                defer.resolve([job, info.floors, info.settings]);
            });
        });

    return defer.promise;
}

Take 2:

jobinfo: function(Jobs, Floor, JobSetting, $stateParams, $q) {

    return Jobs.getByIndex($stateParams.index)
        .then(function(job) {
            console.log('got jobs');
            return $q.all({floors: Floor.getByJob(job), settings: JobSetting.getByJob(job)})
            .then(function(info) {
                console.log('got info');
                return [job, info.floors, info.settings];
            });
        });
}

Both fail. I do not even get a console.log back. I left the rest of the code out, obviously they are wrapped in :

resolve: {
...
}

and defined in the right place.

2

There are 2 answers

3
avcajaraville On BEST ANSWER

I like to separate the resolvers.

You can inject the value on each resolver this way:

job : function( Jobs, $stateParams, $q ) {
    var defer = $q.defer();
    Jobs.getByIndex( $stateParams.index, function( job ) {
        defer.resolve( job );
    });
    return defer.promise;
},

floor : function( Floor, job, $q ) {
    var defer = $q.defer();
    Floor.getByJob( job, function( floor ) {
        defer.resolve( floor );
    });
    return defer.promise;
},

settings : function( JobSetting, job, $q ) {
    var defer = $q.defer();
    JobSetting.getByJob( job, function( settings ) {
        defer.resolve( settings );
    });
    return defer.promise;
},

From ui-router documentation:

The resolve property is a map object. The map object contains key/value pairs of

  • key – {string}: a name of a dependency to be injected into the controller.
  • factory - {string|function}:

[...]

if function, then it is injected and the return value is treated as the dependency. If the result is a promise, it is resolved before the controller is instantiated and its value is injected into the controller.

3
simon On

Try this

jobinfo: function(Jobs, Floor, JobSetting, $stateParams, $q) {

              var defer = $q.defer();

              Jobs.getByIndex($stateParams.index)
                  .then(function(job) {
                      console.log('got jobs');
                      var floors = Floor.getByJob(job);
                      var settings = JobSetting.getByJob(job);
                      $q.all([floors, settings])
                      .then(function(info) {
                          console.log('got info');
                          defer.resolve([job, info[0], info[1]]);
                      });
                  });

              return defer.promise;
          }