I have the following code, but I'm not sure how to add a success/error handler to the request.
$resource('/example.json', {}, {
get_something:
method: 'POST'
url: '/example/get_something.json'
})
I thought I would be able to add success: or something similar here, but apparently that's not the case. How can I do something after this request is completed?
You can handle the response (success/error/exception) as follows:
var example = $resource('/example.json', {}, {
get_something: {
method: 'GET'
}
});
var postParams = {}; // Define post params if any. If you have any post params just use example.get_something()
example.get_something(postParams)
.$promise.then(function(response) {
console.log(response);
}, function(error) {
console.log(error);
})
.catch(function(exception) {
console.log(exception);
});
Related
i want to use $promise.then(successCallback,errorCallback) after the interceptor did the basic message handling. Somehow it always runs into the successCallback and never into the errorCallback if i get error 400,401 etc. If i remove the interceptor it works fine. I also found out that i could create a new promise in the interceptors to solve this problem but i think this is not the best way to go. In my case i only want an interceptor for some basic message handling and then continue in the main controller with the main logic. This is currently not possible because i always run into the successCallback if i get an error.
Did i understand something wrong?
Here an example what i want:
var resourceObj = $resource("url/abc/:action/:id", {}, {
getMember: {
method: 'GET',
params: { action: 'member' },
interceptor: {
responseError: function(response) {
console.log("Interceptor responseError");
//Show some default error messages here
return response; //create new promise with $http(response); to solve the problem?
},
response: function(response) {
console.log("Interceptor responseSuccess");
//Show some default success messages here
return response; //create new promise with $http(response); to solve the problem?
}
}
}
});
myModule.controller('myCtrl', function($scope) {
$scope.checkMember() = function(memberId) {
resourceObj.getMember({ id: memberId }, {}).$promise.then(
function(responseOK) { //successCallback
console.log(responseOK);
$scope.testMember = responseOK.data; // or if no interceptor is used responseOK.toJSON()
//do some stuff here after async call is finished
},
function(responseError) { //errorCallback, never called in error case if an interceptor is used.
console.log(responseError);
//do maybe some advanced error handling here after async call is finished
}
);
}
});
It is important to re-throw the error response.
var resourceObj = $resource("url/abc/:action/:id", {}, {
getMember: {
method: 'GET',
params: { action: 'member' },
interceptor: {
responseError: function(response) {
console.log("Interceptor responseError");
//Show some default error messages here
̶r̶e̶t̶u̶r̶n̶ ̶r̶e̶s̶p̶o̶n̶s̶e̶;̶
//IMPORTANT re-throw error response
throw response;
},
response: function(response) {
console.log("Interceptor responseSuccess");
//Show some default success messages here
return response;
}
}
}
});
If the error response is simply returned, it will be erroneously converted from a rejection to a success.
with $http, we can do this:
var config = { headers: { 'something': 'anything' } };
$http.get('url/to/json', config)
.success(function() {
// do something…
})
i would like to do the same with a $resource reference (not working):
var config = { headers: { 'something': 'anything' } };
MyResource.get(
config,
function() { // success
// do something…
}
);
with the corresponding service declared like this :
.factory('MyResource', function($resource){
return $resource('url/to/json');
})
it's not working : the config object goes to the url and not in the http headers.
Is there a way to do that ?
headers for $resource is available since AngularJS 1.1.1. Make sure you have correct version used.
The format is
$resource('url/to/json', {}, {headers: { 'something': 'anything' }});
[edit by zuma]
The above doesn't seem right. The third parameter to $resource should be a different. This seems more correct to me:
$resource('url/to/json', {}, {
get: {
method: 'GET',
headers: { 'something': 'anything' }
}
});
The headers object inside a resource action supports both static values for its fields, but also dynamic values returned from a function.
$resource('url/to/json', {}, {
get: {
method: 'GET',
headers: {
'header_static': 'static_value',
'header_dynamic': dynamicHeaderVal
}
}
});
function dynamicHeaderVal(requestConfig){
// this function will be called every time the "get" action gets called
// the result will be used as value for the header item
// if it doesn't return a value, the key will not be present in the header
}
Demo Code
angular.module('Test',['ngResource'])
.controller('corsCtrl', function ($scope, $http, MyResource) {
$http.defaults.headers.common['test']= 'team'; //Using $http we can set header also
MyResource.get();
})
.factory('MyResource', function($resource) { //Services
return $resource('url/to/json');
})
JsFiddle DEMO
see in Request Header
To use "Content-Type" header you may need to specify a data body at least for versions around 1.4.7+ due to $http deleting headers without a data body that are === 'content-type'. See #10255 in 1.4.7/angular.js
I just set "data: false" to spoof it, without specifying a data body:
$resource('url/to/json', {}, {
get: {
method: 'GET',
data: false,
headers: { 'something': 'anything' }
}
});
You can set dynamic one-off headers by accessing the config API object in the resource
Demo Code
angular.
.factory('Resource',['$resource',function($resource){return $resource(baseUrl+'/resource/:id', {id: '#_id'}, {
update : {
method : 'POST',
url : baseUrl+'/resource/:id',
headers : {
'custom-header': function(config) {
// access variable via config.data
return config.data.customHeaderValue;
}
},
transformRequest: function(data) {
// you can delete the variable if you don't want it sent to the backend
delete data['customHeaderValue'];
// transform payload before sending
return JSON.stringify(data);
}
}
});
}]);
To execute
Resource.update({},{
customHeaderValue: setCustomHeaderValue
},
function (response) {
// do something ...
},function(error){
// process error
});
My service code:
application.factory('Http', function($http) {
var base_url = "Angular_Database/server.php";
return {
post: function(form_data) {
var request = $http({
method: 'POST',
url: base_url,
data: form_data
});
return request;
},
send: function(request, callback) {
request.then(function(response) {
callback(response);
}).error(function(Object) {
alert(Object.data);
});
}
}
})
here, The problem is in the .then().
My console says:
Type:Error request.then(...) error is not a function
There is no error() function in the HttpPromise object starting from Angular 1.5.X (Based on comment). You need to use catch() function instead of it.
request.then(function(response) {
callback(response);
}).catch(function(Object) {
alert(Object.data);
});
Also could be:
request.then(function(response) {
callback(response);
}, function(error){
alert(error.data);
})
I have two $http posts that each post arrays of objects in a loop. The problem is that the second $http post is reliant on the first one completing. Is there a way to make them not async calls? I tried to used deferred but something is wrong in it as it is not working. It still fires group saving while tag saving is going on.
Angular:
var deferred = $q.defer();
var all = $q.all(deferred.promise);
for (var property in data.tagAdded) {
if (data.tagAdded.hasOwnProperty(property)) {
$http({
method: "POST",
url: '/api/projects/' + data.Project.Id + '/tags',
data: ({ Name: data.tagAdded[property].tag.Name })
}).success(function (response) {
deferred.resolve(response);
data.tagAdded[property].tag.Id = response.Data[0].Id;
data.tagAdded[property].tag.ProjectId = response.Data[0].ProjectId;
}).error(function (response) {
tagError = true;
$.jGrowl("Error saving new tags. Contact support.", { header: 'Error' });
});
}
}
deferred.promise.then(function() {
console.log(data);
});
all.then(function() {
groups.forEach(function(group) {
$http({
headers: { 'Content-Type': 'application/json; charset=utf-8' },
method: "POST",
url: '/api/projects/' + data.Project.Id + '/recruiting-groups',
data: angular.toJson(group, false)
}).success(function(response) {
}).error(function(response) {
recError = true;
$.jGrowl("Error saving recruiting group. Contact support.", { header: 'Error' });
});
});
});
Going without promises is totally not what you want to do here. In fact, this is exactly the kind of situation where promises shine the most! Basically, you weren't using $q.all properly. You can just pass it a list of promises, and it will be resolved when they are all resolved. If any one of them fails, it will yield a rejected promise with the same rejection as the first one that failed. You can of course swallow that rejection via a .catch invocation that returns anything other than a $q.reject value.
I reimplemented what you had using promises. Both .success and .error are fairly limited, so I used the traditional .then and .catch methods here.
/**
* Here we define a function that takes a property, makes a POST request to
* create a tag for it, and then appends the promise for the request to a list
* called tagRequests.
*/
var tagRequests = [];
var createTag = function(property) {
tagRequests.push($http({
method: "POST",
url: '/api/projects/' + data.Project.Id + '/tags',
data: ({ Name: data.tagAdded[property].tag.Name })
}).then(function(response) {
var responseData = response.data;
data.tagAdded[property].tag.Id = responseData.Data[0].Id;
data.tagAdded[property].tag.ProjectId = responseData.Data[0].ProjectId;
return responseData;
}).catch(function (err) {
var errorMsg = "Error saving new tags. Contact support.";
$.jGrowl(errorMsg, { header: 'Error' });
// If we don't want the collective promise to fail on the error of any given
// tag creation request, the next line should be removed.
return $q.reject(errorMsg);
}));
};
/**
* We then iterate over each key in the data.tagAdded object and invoke the
* createTag function.
*/
for (var property in data.tagAdded) {
if (Object.prototype.hasOwnProperty.call(data.tagAdded, property)) {
createTag(property);
}
}
/**
* Once all tag requests succeed, we then map over the list of groups and
* transform them into promises of the request being made. This ultimately
* returns a promise that is resolved when all group POST requests succeed.
*/
$q.all(tagRequests)
.then(function(tagsCreated) {
return $q.all(groups.map(function(group) {
return $http({
headers: { 'Content-Type': 'application/json; charset=utf-8' },
method: "POST",
url: '/api/projects/' + data.Project.Id + '/recruiting-groups',
data: angular.toJson(group, false)
}).then(function(response) {
return response.data;
})
.catch(function(err) {
var errorMsg = "Error saving recruiting group. Contact support.";
$.jGrowl(errorMsg, { header: 'Error' });
// If we want this collective promise to not fail when any one promise is
// rejected, the next line should be removed.
return $q.reject(errorMsg);
});
}));
});
I highly suggest brushing up on Promises in general, and then taking another look at the $q documentation. I've also written this blog post on the way promises work in Angular and how they differ from most promise implementations.
This is exactly what promises do. Angular uses Kris Kowal's Q Library for promises. Check out the Angular docs page, has a perfect example of the promise pattern. Basically you would do the first call, then once it's promise returns success, make the second call.
I had to alter my code a bit, and get some coworker team work. I went completely without promises.
I use a counter to track when counter = 0 by adding to the counter then upon success/fail i decrement from the counter taking it backwards for each completed transaction. When counter is at 0 I am done then call my next bit $http post.
Angular Deferred:
var counter = 0;
var tags = [];
for (var property in data.tagAdded) {
if (data.tagAdded.hasOwnProperty(property)) {
tags.push({ Name: property });
}
}
if (tags.length == 0) {
groupInsert();
} else {
tags.forEach(function (tag) {
counter ++;
$http({
method: "POST",
url: '/api/projects/' + data.Project.Id + '/tags',
data: ({ Name: tag.Name })
}).success(function (response) {
console.log(response)
counter--;
data.tagAdded[property].tag.Id = response.Data[0].Id;
data.tagAdded[property].tag.ProjectId = response.Data[0].ProjectId;
if (counter == 0) {
groupInsert();
}
}).error(function (response) {
counter--;
tagError = true;
$.jGrowl("Error saving new tags. Contact support.", { header: 'Error' });
if (counter == 0) {
groupInsert();
}
});
});
}
function groupInsert() {
groups.forEach(function (group) {
console.log(group)
$http({
headers: { 'Content-Type': 'application/json; charset=utf-8' },
method: "POST",
url: '/api/projects/' + data.Project.Id + '/recruiting-groups',
data: angular.toJson(group, false)
}).success(function (response) {
}).error(function (response) {
recError = true;
$.jGrowl("Error saving recruiting group. Contact support.", { header: 'Error' });
});
});
}
Can anyone explain how can i make a post request with some values in the body of the request in Angularjs?
I tried this solution:
'getNomeServizio':
{ method: "POST",
url: basePath,
headers : {'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'}
}
In my controller:
(new Service()).$getNomeServizio(
$.param({chiave1: valore1, chiave2: valore2'})
).then(function (data) {
...
}, function (error) {
....
})
I want to use $resource but the request doesn't pass form-parameters.
Thanks in advance.
Try this:
Service.getNomeServizio({chiave1: 'valore1', chiave2: 'valore2'}, function(){
//success
}, function(){
//error
})