AngularJS $http call in a Service, return resolved data, not promises

可紊 提交于 2019-11-27 22:18:12

There are two ways I can think of to do this. The first is definitely better than the second.

The first way: using the resolve property of routes

You can use the resolve property of the route configuration object to specify that a promise must be resolved and the resolved value be used for the value of one of your controller dependencies, so that as soon as your controller runs, the value is immediately available.

For example, say you have the following service:

app.service('things', ['$http', '$q', function ($http, $q) {
    var deferred = $q.defer();

    $http({
        method: 'GET',
        url: '/things',
        cache: true
    }).success(function (data) {
        deferred.resolve(data);
    }).error(function (msg) {
        deferred.reject(msg);
    });

    return deferred.promise;
}]);

Then you could define your route something like this:

$routeProvider.when('/things', {
    controller: ['$scope', 'thingsData', function ($scope, thingsData) {
        $scope.allThings = thingsData;
    }],
    resolve: {
        thingsData: ['things', function (things) {
            return things;
        }]
    }
});

The key in the resolve object corresponds to the name of the second dependency for the controller, so even though it returns a promise, that promise will be resolved before the controller is run.

The second way: Make the request well before you need the data

The second way, which is not at all ideal, and will likely bite you on the bum at some point, is to make the request for the data early on, such as when your app is initialised, and then actually get the data later on, say on a page that requires 3 clicks to get to from the home page. Fingers crossed, if the stars have aligned, your http request will have returned by then and you will have the data to use.

angular.module('myModule').factory('myService', ['$http', '$q', function($http, $q) {
    var data = [];

    function fetch() {
        $http.get('/server/call').then(function (d) { data = d; });
    }

    // Public API
    return {
        fetchData: fetch,
        myServiceCall: function () {
            return data;
        }
    };
}]);

Then, in your module's run function, make the request:

angular.module('myModule').run(['myService', function (myService) {
    myService.fetchData();
});

Then, in a controller for a page that is guaranteed to run at least 3 seconds after the app starts, you could do as you suggested:

 angular.module('myModule').controller('deepPageCtrl', ['$scope', 'myService', function ($scope, myService) {
      $scope.data = myService.myServiceCall();
      if (angular.isArray($scope.data) && $scope.data.length === 0) {
           panic("data isn't loaded yet");
      }
  }]);

Bonus, equally bad third way: Synchronous AJAX request

Do as ricick suggests, and use the synchronous AJAX request possible with jQuery's .ajax() method.

This is not possible, as http calls are inherently asynchronous. That is, you need to wait for the server to respond.

The $resource service kind of gets around this by returning a proxy object that is populated with the returned data on server response, but it's still not fully resolved in one line.

Edit:

It is actually possible to make synchronous http requests with the jquery ajax method, by setting the "async" option to false.

You could create a service that wraps this, however your application will "lock up" while the request waits for a server response, so for most cases this would be bad practice. There are also other restrictions on this type of request.

See the docs for more detail:

http://api.jquery.com/jQuery.ajax/

Boris Charpentier

Long time ago (in angular land, actually sometime last year) it was actually how it works.

But now it's no more the case, I think it's due to behavior differences of promise in view and controller, more here about the deprecation : Angularjs promise not binding to template in 1.2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!