Streetsouls
Streetsouls

Reputation: 245

Angular-UI Router - Resolve not waiting for promise to resolve due state switching

I know there is already a similar question Angular-UI Router - Resolve not waiting for promise to resolve? but is not exactly like my problem.

I have two states:

.state('entities', {
    url: '/',
    ...
    resolve: {
       data: function (xyzService) {
          return xyzService.listEntities();
       }
 })

 .state('entities1', {
    url: '/entities1',
    ...
    resolve: {
       data: function (xyzService) {
          return xyzService.listEntities();
       }
 })

And both states require or depends on the same collection of entities, which I return from xyzServce.listEntities(). This service method from its side returns an array from entities and returns a promise.

So I expect to have this 'data' in the controller before to use it. All works perfectly when to use the controller's 'data' for the fist time when the state is called. The problem comes, when I call for example first state 'entities' after that state 'entities1' and finally state 'entities'. So at this step in state 'entities' resolve does not wait to resolve all dependency and in the controller for this state I have 'data' with no array elements and $resolved property to false and an empty $promise object.

So could you tell me why is this behavior? Should I expect each time when the state is called to have resolved the dependency, or this works by specification only for the first time when the page is called?

Could you give me some ideas how to resolve this problem?

Best Regards,

Requested example of the service:

    angular
        .module(SECURITY_MODULE)
        .factory('roleService', roleService);

    roleService.$inject = ['$resource', 'DOMAINS', 'notificationService', '$filter'];

    function roleService($resource, DOMAINS, notificationService, $filter) {
        var service = {
            ...
            listRoles: listRoles
            ...
        };

        var roleResource = $resource(DOMAINS.api + 'roles/:id/:command/:command2', {id : '@id'}, {
            ....
            'listRoles': {method: 'GET', isArray: true}
        });

        function listRoles(callbackSuccess, errorCallback) {
            var roles = roleResource.listRoles(function() {
                callbackSuccess && callbackSuccess(roles);
            }, function(error) {
                errorCallback && errorCallback(error);
            });

            return roles;
        }
....
    return service;
}

Upvotes: 2

Views: 1688

Answers (2)

Andreas Jägle
Andreas Jägle

Reputation: 12240

As listed in the docs, the resource immediately returns a value (empty object or empty array), then fetches the data and later assigns it.

https://docs.angularjs.org/api/ngResource/service/$resource

It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view.

This works fine when used directly inside a controller but doesn't work with the router's resolve, because for the router library, the value is already resolved with the initial value.

So as @Dmitriy noted, you should use the promise of the resource, that is provided via the $promise field. This will not resolve before the value is present or an error occured.

For more details see this great post on the topic: http://www.jvandemo.com/how-to-resolve-angularjs-resources-with-ui-router/

Upvotes: 3

Dmitriy Nevzorov
Dmitriy Nevzorov

Reputation: 6078

If you use angular $resource you should return xyzService.listEntities().$promise

https://docs.angularjs.org/api/ngResource/service/$resource

Upvotes: 3

Related Questions