angularjsnestedangular-ui-routerpromiseresolve

Nested promises in ui-router resolve


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.


Solution

  • 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.