Get response header in then() function of a ngResource object's $promise property after resource resolved?
Asked Answered
P

3

12

I'm willing to retrieve the response header of a resource request, cause I've put pagination information and something else in it rather than the response body, to make the REST api clear.

Though we can get it from the success / error callback like below:

Object.get({type:'foo'}, function(value, responseHeaders){
    var headers = responseHeaders();
});

Where 'Object' is my resource factory service.

Further, when I'm trying to make the route change after required resources resolved, I've tried this:

.when('/list', {
    templateUrl: 'partials/list.html',
    controller: 'ListCtrl',

    // wait for the required promises to be resolved before controller is instantialized
    resolve: {
        objects: ['Object', '$route', function(Object, $route){
            return Object.query($route.current.params).$promise;
        }]
    }
})

and in controller, just inject "objects" instead of Object service, because it's resolved and filled in with real data.

But I got problem when I try to get headers info from the "objects" in controller.

I tried objects.$promise.then(function(data, responseHeaders){}), but responseHeader was undefined.

How can I change the $resource service's behavior so that it throws the responseHeader getter into the $promise then() callback function?

My service "Object" for reference:

myServices.factory('Object', ['$resource',
    function($resource){
        return $resource('object/:id', {id: '@id'}, {
            update: {method: 'PUT'},
        });
    }
]);
Pardoes answered 6/4, 2014 at 18:40 Comment(1)
You say responseHeader was undefined, but the parameter in your function definition is responseHeaders (plural), so responseHeader (singular) should indeed be undefined?Andante
G
10

I had the exact same problem. I used an interceptor in the resource definition to inject the http headers in the resource.

$resource('/api/resource/:id', {
    id: '@id'
  }, {
    index: {
      method: 'GET',
      isArray: true,
      interceptor: {
        response: function(response) {
          response.resource.$httpHeaders = response.headers;
          return response.resource;
        }
      }
    }});

Then, in the then callback, the http headers are accesible through $httpHeaders:

promise.then(function(resource) {
    resource.$httpHeaders('header-name');
});
Gamo answered 2/1, 2016 at 18:7 Comment(1)
In case the above solution it's not working it might be a CORS problem so look at answer to this problem: #33257820. That solution worked for me.Scabble
M
5

I think I had a similar problem: After POSTing a new resource I needed to get the Location header of the response, since the Id of the new resource was set on the server and then returned via this header.

I solved this problem by introducing my own promise like this:

app.factory('Rating', ['$resource',
    function ($resource) {

        // Use the $resource service to declare a restful client -- restangular might be a better alternative
        var Rating = $resource('http://localhost:8080/courserater/rest/ratings-cors/:id', {id: '@id'}, {
            'update': { method: 'PUT'}
        });

    return Rating;
}]);

function RestController($scope, $q, Rating) {
  var rating = new Rating();
  var defer = $q.defer(); // introduce a promise that will be resolved in the success callback
  rating.$save(function(data, headers){ // perform a POST
      // The response of the POST contains the url of the newly created resource
      var newId = headers('Location').split('/').pop();
      defer.resolve(newId)
    });
    return defer.promise;
  })
  .then (function(newId) {
    // Load the newly created resource
    return Rating.get({id: newId}).$promise; // perform GET
  })
  .then(function(rating){
    // update the newly created resource
    rating.score = 55;
    return rating.$update(); // perform PUT
  });
}
Mingrelian answered 8/4, 2014 at 21:19 Comment(1)
This is the exact business case I have as well, but wondering if we can do it with the $promise.then() callback?Cumulus
T
3

We can't use .then for returning the header because the promise doesn't allow for multiple return values. (e.g., (res, err))

This was a requested feature, and was closed https://github.com/angular/angular.js/issues/11056

... the then "callbacks" can have only [one] argument. The reason for this is that those "callbacks" correspond to the return value / exception from synchronous programming and you can't return multiple results / throw multiple exceptions from a regular function.

Targe answered 30/6, 2015 at 0:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.