I'm constructing elements from metadata and i need to set a calculated class for each element.
This is what I currently do,
var promisses =_.map(templates, function (tmpl) {
return $http.get(tmpl.template, {
cache : $templateCache,
// Generated class name is carried to the resolving function using the config
classes : scope.generate_class(tmpl.columns)
}).then(function (data) {
if ( data.status != 200 )
throw new Error('Failed to fetch template');
var elm = angular.element(data.data);
elm.addClass(data.config.classes);
return elm;
});
});
$q.all(promisses).success....
If I want to use success instead of then fir the $http bit (which evaluates in case of an error as well) how would i do that ? when using success the config is not carried on to the resolving function (only the data).
Thanks.
From $http docs:
Returns a promise object with the standard then method and two http
specific methods: success and error. The then method takes two
arguments a success and an error callback which will be called with a
response object. The success and error methods take a single argument
- a function that will be called when the request succeeds or fails respectively. The arguments passed into these functions are
destructured representation of the response object passed into the
then method.
The response object has these properties:
data – {string|Object} – The response body transformed with the transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to generate the request.
statusText – {string} – HTTP status text of the response.
So you can pass the config like so:
.success(function(data, status, headers, config) {
Do not throw errors when using promises, if your server doesn't return an error code you can use q.reject to transform it to a rejection, also q.all promises doesn't have a success method:
var promisses =_.map(templates, function (tmpl) {
return $http.get(tmpl.template, {
cache : $templateCache,
// Generated class name is carried to the resolving function using the config
classes : scope.generate_class(tmpl.columns)
}).then(function(res) {
if ( res.status != 200 ) {
return $q.reject('Failed to fetch template');
} else {
var elm = angular.element(res.data);
elm.addClass(res.config.classes);
return elm;
}
});
});
$q.all(promisses)
.then(function() { ... })
.catch(function() { .. })
Related
I have a Api in which retrieves a custom header: X-Total-Count : "total of items", I'm using angular with ngResource.
My factory look like this:
app.factory("shopFactory", function ($resource) {
return {
User: $resource("http://localhost:58495/users/api/User/?id=:id", { id: "#id" }),
Category: $resource("http://localhost:58495/category/:id", { id: "#id" }),
Product: $resource("http://localhost:58495/products/?from=:from&to=:to", { from: "#from", to: "#to" })
};
});
And when I call it:
var productServer = shopFactory.Product.query({ from: 0, to: 10 }).$promise.then(function (response) {
$scope.product = response;
console.log(response);
}, function (error) {
console.log("ERROR");
console.log(error);
});
How can I access my custom header through ngResource, I can access it but with $http, I want to do it with the $resource way, Thanks
The query action method can be called with three arguments:
Resource.query([parameters], [success], [error])
The success callback is called with (value (Object|Array), responseHeaders (Function), status (number), statusText (string)) arguments, where the value is the populated resource instance or collection object. The error callback is called with (httpResponse) argument.
var productServer = shopFactory.Product.query(
{ from: 0, to: 10 },
function success (value, headers, status, statusText) {
$scope.product = value;
console.log(value);
console.log(headers());
},
function error (error) {
console.log("ERROR");
console.log(error);
}
);
For more information, see AngularJS $resource Service API Reference.
whats the difference between using $promise.then and the success function,
The function in the .then method exposes only the value of the final response. While the success callback exposes four arguments: value (Object|Array), responseHeaders (Function), status (number), statusText (string).
The $promise can be passed as an argument to other functions and its .then method can be invoked multiple times.
Another very important difference is that the .then method creates a new promise from values returned.
Chaining promises
Because calling the .then method of a promise returns a new derived promise, it is easily possible to create a chain of promises.
It is possible to create chains of any length and since a promise can be resolved with another promise (which will defer its resolution further), it is possible to pause/defer resolution of the promises at any point in the chain. This makes it possible to implement powerful APIs.
— AngularJS $q Service API Reference (Chaining Promises)
As you guys know, Angular recently deprecated the http.get.success,error functions. So this kind of calls are not recommended in your controller anymore:
$http.get("/myurl").success(function(data){
myctrl.myobj = data;
}));
Rather, this kind of calls are to be used:
$http.get("/myurl").then(
function(data) {
myctrl.myobj = data;
},
function(error) {
...
}
Problem is, simple Spring REST models aren't working with this new code. I recently downloaded a sample code with the above old success function and a REST model like this:
#RequestMapping("/resource")
public Map<String,Object> home() {
Map<String,Object> model = new HashMap<String,Object>();
model.put("id", UUID.randomUUID().toString());
model.put("content", "Hello World");
return model;
}
This should return a map like {id:<someid>, content:"Hello World"} for the $http.get() call, but it receives nothing - the view is blank.
How can I resolve this issue?
The first (of four) argument passed to success() is the data (i.e. body) of the response.
But the first (and unique) argument passed to then() is not the data. It's the full HTTP response, containing the data, the headers, the status, the config.
So what you actually need is
$http.get("/myurl").then(
function(response) {
myctrl.myobj = response.data;
},
function(error) {
...
});
The expectation of the result is different. Its the response and not the data object directly.
documentation says :
// Simple GET request example:
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Properties of the response are
data – {string|Object} – The response body transformed with the transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to generate the request.
statusText – {string} – HTTP status text of the response.
As the data object is required,
Please convert the code as
$http.get("/resource").then(
function(response) {
myctrl.myobj = response.data;
});
then must be return a new promise so you should handle it with defers.
var myApp = angular.module('myApp', []);
myApp.factory('modelFromFactory', function($q) {
return {
getModel: function(data) {
var deferred = $q.defer();
var items = [];
items.push({"id":"f77e3886-976b-4f38-b84d-ae4d322759d4","content":"Hello World"});
deferred.resolve(items);
return deferred.promise;
}
};
});
function MyCtrl($scope, modelFromFactory) {
modelFromFactory.getModel()
.then(function(data){
$scope.model = data;
})
}
Here is working fiddle -> https://jsfiddle.net/o16kg9p4/7/
I wish to implement a service which has the following features:
Performs a HTTP request to a given resource only once.
Provides two exported functions, each of which return a promise, where the promise is resolved based on data from the one-time HTTP call.
The two functions shall exist to provide different representations of the fetched data.
The outline of my service so far is as follows:
angular.module('someApp')
.service('someService', function ($http) {
var httpPromise = $http.get('/some/endpoint/').then(
function(response) {
// HTTP response data is processed
});
this.getSomePromise = function() {
// Return a promise which is resolved using one representation of HTTP response
}
this.getAnotherPromise = function() {
// Return a promise which is resolved using another representation of HTTP response
}
});
If there was only the need for one 'getter' function then clearly I could simply have returned the httpPromise.
What is the appropriate way to implement the interface as shown? Is it possible for two or more consumers to call .then() on the same promise, in which case I could merely return httpPromise.then(function(){...modify data...}) from both functions? Or, in this scenario would it be necessary to create a new promise (using $q.defer()) and resolve it somehow based on a cache object which holds the HTTP response?
You can simply create two promises, using chaining, on the http promise:
var httpPromise = $http.get('/some/endpoint/');
var firstPromise = httpPromise.then(function(response) {
return firstTransformation(response.data);
});
var secondPromise = httpPromise.then(function(response) {
return secondTransformation(response.data);
});
this.getSomePromise = function() {
return firstPromise;
}
this.getAnotherPromise = function() {
return secondPromise;
}
How do you catch errors/read http status code when making a rest call in one of these formats, both work to return a successful response, just no idea how to grab the info i need. I can get the object with values returned as I need, I just cant get the http status code.
methods provided by #Claies in a response to this question (Get data from $resource response in angular factory)
$scope.makeRestCall= function () {
$scope.member = Item.makeRestCallWithHeaders('123456789', '789456123')
.query().$promise.then(function(response){
});
};
$scope.makeRestCall= function () {
$scope.member = Item.makeRestCallWithHeaders('123456789', '789456123')
.query({}, function() {
})
};
I have tried to use the first method here and grab something from the function(response) such as response.status, but it returns undefined.
For reference, using this factory:
.factory("Item", function($resource) {
var endpoint = "http://some valid url";
function makeRestCallWithHeaders(id1, id2) {
return $resource(endpoint, null, {
query: {
method: 'GET',
headers: {
'id1': id1,
'id2': id2
}
}
})
}
var item = {
makeRestCallWithHeaders: makeRestCallWithHeaders
}
return item ;
})
Item returns something like this:
{firstName:Joe, lastName:smith}
I am really just trying to figure out how I can access the status code returned by the REST call. Absolute end goal is to read any error response and return error to UI written in angular as well. If there is a way to just read this in the UI, that could work too.
To read the error status you need to pass in the errorCallback to the $promise:
$scope.makeRestCall= function () {
$scope.member = Item.makeRestCallWithHeaders('123456789', '789456123')
.query().$promise.then(
function(response){
//this is the successCallback
//response.status & response.statusText do not exist here by default
//because you don't really need them - the call succeeded
//see rest of answer below if you really need to do this
// but be sure you really do...
},
function(repsonse) {
//this is the errorCallback
//response.status === code
//response.statusText === status text!
//so to get the status code you could do this:
var statusCode = response.status;
}
);
};
You shouldn't need the status in the successCallback, because it is a success and you know the success code implicitly.
Therefore the status is not available in the successCallback by default.
If, for some reason, you do need the status in your successCallback, you could write an interceptor to put this information somewhere, but be aware that the angular framework deals with the data differently in different success scenarios so you will need to write code for different cases.
I have the following:
$resource('/api/:et/:id', { et: $scope.data.entityType })
.delete({ id: entityId }, deleteSuccess, error)
.$promise.finally(last);
How can I find out what response code is returned if the the $resource completes with a success or error ?
In case of errors your error handler will be called with a single parameter (httpResponse), so you can look up the HTTP status in its status property:
function error(httpResponse) {
var status = httpResponse.status;
}
Success callbacks are called with two parameters: (value, httpHeaders). httpHeaders is a function returning an object with all HTTP response headers if invoked without parameters, or the value of a single header if invoked with a header name:
function deleteSuccess(value, httpHeaders) {
var allHeaders = httpHeaders(); // all headers
var contentType = httpHeaders('content-type'); // response content type
}
(see the docs for $resource for more details).