I've been digging at this but cannot figure this one out, here's the simple attempt I've made, I thought this was fine but it seems to still request as get....
this.request = function(url, requestData) {
return $resource(url, null, {
post : {
method : 'POST',
params : requestData || {}
}
});
};
Using it:
this.request('/some/api/url', {data : true}).post();
I can't seem to figure out how to get back a promise object so that I can use the repsonse data....
You want to create your resource like so:
$resource(url, null, {
post: {
method: 'POST'
}
});
And then:
this.request.post(
requestData,
function (successResponse) {
// Do whatever with response
},
function (failResponse) {
// Do whatever with response
}
);
This will send a POST request to url with requestData as the body.
Related
I'm writing a response intercepter for an API call with ngResource like this:
var Thing = $resource('/api/things/:id', {id: '#id'}, {
queryAll: {
method: 'GET',
interceptor: {
response: function(response) {
var instance = response.resource;
doAsyncStuffHere(instance.data);
return instance;
}
}
}
});
The interceptor function should enrich the data from the response but returns the unmodified instance before the async stuff is done (as expected, since it's async...).
Is there a good way, to enrich the data asynchronously and make the return statement "wait" until it's done? Callback? Promise?
After searching the right question, i've found an article who solved my issue:
Sometimes there is a need to make some asynchronous operations inside the interceptor. Luckily AngularJS allows us to return a promise that will be resolved later. This will defer the request sending in case of request interceptor and will defer the response resolving in case of response interceptor.
From: http://www.webdeveasy.com/interceptors-in-angularjs-and-useful-examples/
And here is what my code now looks like and working like a charm.
var Thing = $resource('/api/things/:id', {id: '#id'}, {
queryAll: {
method: 'GET',
interceptor: {
response: function(response) {
var instance = response.resource,
_deferred = $q.defer();
doAsyncStuffHere(instance.data).then(function() {
_deferred.resolve(instance);
});
return deferred.promise;
}
}
}
});
Use o exemplo:
https://docs.angularjs.org/api/ng/service/http#$http-arguments;
A propriedade "transformRequest" é uma melhor opção;
I am try to post data form $resource in angular js project. It is my code in factory
deletemenu: function(menudata ) {
return $resource(url+'/menu/delete', {}, {
delete_menu: {
method: 'POST',
params: {
entityType : menudata.entityType ,
sellerId : menudata.sellerId ,
menuId : menudata.menuId ,
parentMenuIds : menudata.parentMenuIds ,
menuItemId : menudata.menuItemId
},
isArray: false
}
}).deletemenu();
}
I declare method POST but the request is send as a query string not the post request. It send as a
URL+"menu/delete?entityType=I&menuId=25&menuItemId=20&parentMenuIds=4&sellerId=1"
How I send these data as a POST method.
I think this should work better for you
return $resource(url + '/menu/delete', null, {
delete_menu: {method: 'POST'}
}).delete_menu(menudata);
Here, I'm passing in the menudata as the first argument to the non-GET "class" action delete_menu which will use it as postData.
The objects returned by $resource are much more flexible than what you're using here. It looks like you should be able to make your service / factory much neater by returning the $resource instance instead of these individual functions. For example
.factory('menuFactory', function($resource) {
var url = 'whatever';
return $resource(url, null, {
delete: {
url: url + '/menu/delete',
method: 'POST'
} //, other actions here
});
})
Then you can call it with
menuFactory.delete(menuData)
I am using $resource and caching the results of get requests. My problem is that, after post requests, the cache is not being invalidated.
Here is the return value from the service:
return $resource('http://url.com/api/url/:id', {}, {
'query' : {
method : 'GET',
isArray:true,
cache : true
},
'get' : {
method : 'GET',
cache : false
}
})
Here is the save method I am using inside my controller. As you can see, I'm using the callback on the post request to recalculate the query/list of nouns.
var newNoun = new Noun($scope.noun);
newNoun.$save(function(x) {
$scope.nouns = Noun.query();
});
I would like to invalidate the cache after calling post or another non-get method. How could I do this? Is this already built into $resource or do I need to implement it on my own?
You could create a wrapper service to do the caching like you want, for example:
app.factory('cachedResource', function ($resource, $cacheFactory) {
var cache = $cacheFactory('resourceCache');
var interceptor = {
response: function (response) {
cache.remove(response.config.url);
console.log('cache removed', response.config.url);
return response;
}
};
return function (url, paramDefaults, actions, options) {
actions = angular.extend({}, actions, {
'get': { method: 'GET', cache: cache },
'query': { method: 'GET', cache: cache, isArray: true },
'save': { method: 'POST', interceptor: interceptor },
'remove': { method: 'DELETE', interceptor: interceptor },
'delete': { method: 'DELETE', interceptor: interceptor },
});
return $resource(url, paramDefaults, actions, options);
};
});
Then replace any $resource with cachedResource.
Example plunker: http://plnkr.co/edit/lIQw4uogcoMpcuHTWy2U?p=preview
While #runTarm's answer above is great, it does not allow actions to be easily customized from the inheriting service, e.g. the following would not be possible:
app.factory('Steps', function (CachedResource) {
return CachedResource('/steps/:stepId', {}, {
save: { method: 'POST', params: { stepId: '#stepId' } }
});
});
In this case, this definition of save would be replaced by the one present in CachedResource.
Solution
But it can be fixed easily from Angular 1.4 by replacing
actions = angular.extend({}, actions, {
with
actions = angular.merge({}, actions, {
so that both objects are deep-merged.
Even better solution
In the above scenario, action options defined in CachedResource would be preferred over custom configuration in inheriting services. To fix that, switch the order of arguments passed to merge:
actions = angular.merge({}, { /* default options get, query, etc. */ }, actions);
With this solution, the following will work as expected (i.e. use DESTROY instead of default DELETE when calling remove):
app.factory('Steps', function (CachedResource) {
return CachedResource('/steps/:stepId', {}, {
remove: { method: 'DESTROY' }
});
});
$resource is using the default cache for $http.
You can access it using: $cacheFactory.get('$http')
You can remove a key value pair, using the returned caches remove({string} key) method.
E.g.:
var key = '...the key you want to remove, e.g. `/nouns/5`...';
$cacheFactory.get('$http').remove(key);
angularjs code:
$http({
method: 'POST',
url:'/hello/rest/user/test',
data: {user: 'aaaaa'}
});
Server code:
#POST
#Path("/test")
public Response merge(#Context HttpServletRequest request) {
System.out.println(request.getParameter("user"));
if (request.getParameter("user") == null) {
return Response.status(Status.BAD_REQUEST).build();
}
return Response.ok().build();
}
request.getParameter("user") is a null. I cannot revice a parameter by this way.
If you want to use request parameter, you need to pass the data as
$http.post('/hello/rest/user/test', {
user : 'aaaaa'
}, {
headers : {
"Content-Type" : 'application/x-www-form-urlencoded;charset=utf-8'
},
transformRequest : [function(data) {
return angular.isObject(data)
? jQuery.param(data)
: data;
}]
});
Also read this question
You need to look at the body rather than for the post parameter...
You may not be receiving POST parameters.
You are receiving a body that looks like this {"user":"aaaaa"} and you need to parse that JSON response.
My rest api accpets DELETE requests to the following url
/api/users/{slug}
So by sending delete to a specified user (slug) the user would be deleted. here is the service code:
angular.module('UserService',['ngResource']).factory('User', function($resource){
var User = $resource('/api/users/:id1/:action/:id2', //add param to the url
{},
{
delete_user: {
method: 'DELETE',
params: {
id1:"#id"
}
},
update: {
method: 'PUT',
params: {
id1:"#id"
}
}
});
return User;
});
I call the delete function via
user.$delete_user({id:user.id}, function(){}, function(response){});
However the request seems to be send to the wrong url.
/api/users?id=4
So the parameter is actually missing, as a result I get a 405 Method not allowed. Is there any chance to send the delete request in the style of my api?
params is an object of default request parameteres in your actions. If you want url parameters you have to specify them in the second parameter like this:
angular.module('UserService',['ngResource']).factory('User', function($resource){
var User = $resource('/api/users/:id1/:action/:id2', //add param to the url
{id1:'#id'},
{
delete_user: {
method: 'DELETE'
}
});
return User;
});
this works with either:
// user has id
user.$delete_user(function(){
//success
},function(){
// error
});
or
var data = {id:'id_from_data'};
User.delete_user({},data);
or
var params = {id1:'id1_from_params'};
User.delete_user(params);
I've made a plnkr-example - you have to open your console to verify that the DELETE requests are correct.
See parameterDefaults in the Angular resource documentation.
I had this problem for a while I was using a service to add / delete / update categories. While passing in params for get it worked fine but then when deleting it was giving me a ?id=1234 instead of api/resource/1234
I got around this by making the default param a string.
///Controller
Service.delete({categoryId:id}, function(resp){
console.log(resp)//whatever logic you want in here
});
//SERVICES
$resource('api/resource/:categoryId', {"categoryId":"#categoryId"}, {
query:{method:"GET"},
delete:{method:"DELETE"},
});
Should work and the resulting url will be, originally I had categoryId in the default params as a variable name.
api/resource/1234 etc
Just omit the '#' in the parameter
.factory('reportFactory', ['$resource', 'baseUrl', function ($resource, baseUrl) {
return $resource(baseUrl + '/keys/:id', {}, {
delete: { method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
params: {id: 'id'} }
})
}]);
this will give you:
http://localhost:8080/reports/api/keys/b8a8a8e39a8f55da94fdbe6c
without the question mark
If you want to delete a model, there's no need to add params (params does not work for DELETE anyway):
$resource('/users/:id').delete({id: user.id}, function(res) {
...
})
or
$resource('/users/:role/:id').delete({role: 'visitor', id: user.id});
I'm not sure if it's a bug of ngResource.