Skip to content

resolve and $http requests #77

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Starefossen opened this issue Apr 10, 2013 · 16 comments
Closed

resolve and $http requests #77

Starefossen opened this issue Apr 10, 2013 · 16 comments

Comments

@Starefossen
Copy link

How is the resolve supposed to work for asynchronously resolve data when it has no true callback method?

This is what I'm trying to do, but the $timeout method is not behaving like a callback method and hence the $scope.items is never present when the partial is rendered.

In the examples resolve is mentioned along with asynchrony data, but I can not get it to work.

$stateProvider.
  state('test', {
    url: '/test',
    templateUrl: 'partials/test.html',
    resolve: {
      items: ['$timeout', '$stateParams', '$http', function($timeout, $stateParams, $http) {
        $http.get('models/test.json')
          .then(function(res) {
            console.log('http', res);
            $timeout(function() {
              return res.data;
            }, 10);
          })
      }]
    },
    controller: ['$scope', '$state', '$http', function($scope, $state, $http) {
      $scope.title = 'My test page';
    }]
});
@mostr
Copy link

mostr commented Apr 10, 2013

I guess you need to return promise from the function resolving items and your success callback to get should return promise too.

@Starefossen
Copy link
Author

Thanks for the help @mostr. I just realized that resolve is not a angular-ui specific thing, but rather a part of angularjs as a whole, sorry for posting this noobish question here.

Here is the solution that worked for me:

$stateProvider.
  state('test', {
    url: '/test',
    templateUrl: 'partials/test.html',
    resolve: {
      items: ['$http', function($http) {
        return $http({
          method: 'GET',
          url: 'models/items.json'
        });
      }]
    },
    controller: ['$scope', '$state', 'items', function($scope, $state, items) {
      $scope.title = 'My test page';
      $scope.items = items.data; // don't forget to add it here!
    }]
});

@ghost
Copy link

ghost commented Jul 26, 2013

Thanks for posting that solution. The documentation for resolve leaves much to be desired.

@timkindberg
Copy link
Contributor

Please let me know how the resolve docs could be improved. I'm completely open to editing them.

https://github.com/angular-ui/ui-router/wiki#resolve

@ghost
Copy link

ghost commented Jul 26, 2013

Way more examples would be great--all it shows now is how to use the name of a service, but that service seems to do no work. If the documentation says these properties can be either strings or functions, nobody I know would ever guess that you could also feed them an array and expect it to work.

I realize that this is an idiom that Angular has chosen to enforce in many other locations with their attempt to bring named argument support to a language which doesn't want them, but it never looks right no matter how many times you see it elsewhere.

@timkindberg
Copy link
Contributor

Ok, @oncomeme could you do me a favor and look at the revised Resolve docs?

https://github.com/angular-ui/ui-router/wiki#resolve

I want to know if they make more sense and give a more complete picture.

@ghost
Copy link

ghost commented Jul 26, 2013

A couple things I'd still like to see:

  1. What would the service definition actually look like if it needs to perform an XHR through $http()? I'd ideally like to factor my server communications out into a service, but I'm not sure how I can do this given the fact that services are singletons and every request can't share a common promise. If all the router knows is the name of the service, it can't really wait on any specific promise that a specific method defined on that service might return.

  2. An example with a promise that doesn't come bundled with extra functionality from some other part of Angular. Where it says "If the result is a promise, it is resolved before the controller is instantiated and its value is injected into the controller" I'm finding that this is only true when that promise comes directly out of a call to $http(). If I build my own promise with $q.defer() and return that from my function, the controller receives the actual promise object itself when it is resolved, not anything that it was resolved with.

@timkindberg
Copy link
Contributor

Good ideas. I'll add them this weekend.

@ghost
Copy link

ghost commented Jul 26, 2013

I figured out at least part of the problem was that I need to return $q.defer().promise rather than $q.defer() itself, but there is still something, somewhere taking all the arguments passed to the success callback of $http's output and packaging them up as an object full of k/v pairs which does not happen with my own promises.

@timkindberg
Copy link
Contributor

ok I added examples for your suggestions as well. Hopefully that makes it a bit easier for newcomers.

@ghost
Copy link

ghost commented Jul 28, 2013

Thanks. That's very helpful.

@ghost
Copy link

ghost commented Jul 30, 2013

I'm noticing a bizarre chicken-and-egg situation when trying to use the resolve map to invoke a service method, namely if my service requires $stateParams in order to do its work, it shows up empty.

Are these resolve promises being resolved before the router's even parsed this information out of the location? If so, what's the right way to get to this information?

@timkindberg
Copy link
Contributor

I'm pretty certain this issue has been discussed before. Try searching closed issues.

@ghost
Copy link

ghost commented Jul 30, 2013

The closest thing I found is still open, and I think this is a fairly significant gotcha that should either be fixed or documented:

#238

@timkindberg
Copy link
Contributor

Actually I think this is actively being fixed by @ksperling

@SrikumarChari
Copy link

Follow up question... I have this code in the config section:

$stateProvider
        .state('index', {
            url: '/',
            views: {
                '': {
                    templateUrl: './views/layout.html',
                    controller: 'MyAppCtrl'
                },
                'app-navbar@index': {
                    templateUrl: './views/app-navbar.html'
                },
                'app-accordion@index': {
                    templateUrl: './views/app-accordion.html',
                    controller: 'AppController',
                    resolve: {
                        appPromiseObj: function (AppFactory) {
                            return AppFactory.getApps();
                        }
                    }
                },

...

and have the following AppFactory

myApp.factory('AppFactory', function ($http) {
    var appFac = {
        apps: []
    };

    appFac.getApps = function () {
        promiseObj = $http.get('http://localhost:4567/applications').success(function (data) {
            console.log("success calling http");
            angular.copy(data, appFac.apps);
        });
        return promiseObj;
    };
    return appFac;
});

But when I execute, the console.log message in the success callback never gets executed. The browser log shows the http call executes OK with code 200. I am assuming this means angular thinks it has failed or should I be doing something else?

I even tried returning the $q promise object (as suggested in stack overflow) but no success. In the factory code if I use test data (i.e., no HTTP call) everything works fine even if I don't return a promise object. Any pointer on where the problem could be? Appreciate any pointers to help me debug...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants