Angular.js delete resource with parameter - angularjs

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.

Related

Angular js how to pass data to delete service?

I am working in angular js on delete service api when passing data in service it is showing 400 bad request error.This is my js to call the service.
$scope.deleteUser = function(id){
var data = 'Id='+id;
DataService.deleteUser(data).then(function successCallback(response) {
console.log('deleted');
}, function errorCallback(response) {
console.log(response);
});
}
This is service js to delete users.
service.deleteUser = function(data){
var config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Auth-Token': 'mytoken'
}
};
return $http.delete(mainURL + '/users', data, config);
};
This is curl api request where i need to pass data:
curl -v -H "X-Auth-Token: mytoken" -X DELETE -F Id=665799088 http://<ipaddress>/users
The 2nd parameter to $http.delete is the config, so you need to pass the config object as the 2nd parameter and not data.
DELETE method type doesn't accept a Request body so you should not be passing the ID as data. Instead try this http://main_url/users?Id=id
So in your service use this
return $http.delete(mainURL + '/users?Id='+data, config);
Also check how you are passing the ID to your API. If you are passing ID as a query parameter then the above will work, but if you are passing it as a route parameter then the above URL won't work, but from your CURL expression I believe you are passing Id in the Query string and not as a route parameter.
According to documentation on $http service, delete method only accepts 2 parameters, url and config, meaning that your data is currently treated like config. You are most likely looking to pass some params options to your config object.
DataService.deleteUser(id).then(function successCallback(response) {
console.log('deleted');
}, function errorCallback(response) {
console.log(response);
});
And your service declaration should be more like.
service.deleteUser = function(id){
var config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Auth-Token': 'mytoken'
},
params : {
id : id
}
};
return $http.delete(mainURL + '/users', config);
};
Also keep in mind that a path looking like /users/id is more correct, if you are in charge of the API.

add config in angular resource

I am using http-auth-interceptor for authentication. In http-auth-interceptor, I use the following way to login:
var data = 'username=' + encodeURIComponent(user.userId) + '&password=' + encodeURIComponent(user.password);
$http.post('api/authenticate', data, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
ignoreAuthModule: 'ignoreAuthModule'
})
ignoreAuthModule is used to tell ignoreAuthModule that this login method will be ignored by the auth interceptor.
Now, I have some request with $resource, like:
.factory('SomeDataService', function ($resource) {
return $resource('api/some/data', {}, {
'get': { method: 'GET'}
});
})
I want SomeDataService.get() is also ignored by the auth interceptors, because I need to control the 401 error by myself.
So, my question is, is there any way for ngResource that I can set config like that in $http.
[update based on comment]
I have listened the login-required event:
$rootScope.$on('event:auth-loginRequired', function (rejection) {
$log.log(rejection);
// I need to get the request url and for some specific url, need to do something.
$rootScope.loginPopup();
});
But the 'rejection' parameter has no context data of request I need. I need to get the request url and check, for some specified url, I need to do something.
After checking the document of ngResource, I got the solution as below:
.factory('SomeDataService', function ($resource) {
return $resource('api/some/data', {}, {
'get': { method: 'GET', ignoreAuthModule: 'ignoreAuthModule'}
});
})
Just add the config item as above. It will be equivalent ad:
$http.post('api/some/data', data, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
ignoreAuthModule: 'ignoreAuthModule'
})
ngResource module is build on top of $http.Hence it is not possible to configure all the stuffs you can do with $http in $resource.I think the below link will be guide you to have a clear understanding on $http and $resource

AngularJS Response does not match configured parameter

I've got a problem with service configuration. I want to display one user by this function:
$scope.findOne = function() {
$scope.user = Users.get({
userId: $stateParams.userId
});
};
But I am in trouble with User service :( I don't know, how should I change my the code to avoid angular error:
Error in resource configuration for action object. Expected response
to contain an array but got an {2}
Here is a code of my actual working service (without function findOne working of course:))
'use strict';
angular.module('users').factory('Users', ['$resource',
function($resource) {
return $resource('users', {}, {
update: {
method: 'PUT'
},
remove: {
method: 'DELETE',
url: 'users/:id',
params: {id: '#_id'}
}
});
}
]);
At a guess, I'd say your users API endpoint is expecting /users/:userId for GET requests. Your code at the moment will request /users?userId=nnn. You need to add an action for get with the ID in the URL, eg
return $resource('users', {id: '#userId'}, {
get: {
method: 'GET',
url: 'users/:id',
isArray: false
},
// etc
You can also make users/:id the default URL as long as it doesn't interfere with your other action configurations.

MEAN stack user delete

I've got a users list with delete button on /users url. My delete route looks like this:
app.route('/users/:userId')
.get(users.read)
.put(users.updateById)
.delete(users.delete);
app.param('userId', users.userById);
But problem is, that my delete button is calling delete on /users url, so I'm getting DELETE http://localhost:3000/users 404 (Not Found). How can I solve this problem? My controller remove() function you can see below. How can I pass '/user/' + user._id to it? User is removed correctly only from scope :(
$scope.remove = function(id) {
var user = $scope.users[id];
var modalOptions = {
closeButtonText: 'Cancel',
actionButtonText: 'Delete user',
headerText: 'Delete ' + user.displayName + '?',
bodyText: 'Are you sure you want to delete this user?'
};
modalService.showModal({}, modalOptions).then(function() {
if (user) {
user.$remove();
for (var i in $scope.users) {
if ($scope.users[i] === user) {
$scope.users.splice(i, 1); // remove item from scope
}
}
}
});
};
user service is basic from mean.js installation
angular.module('users').factory('Users', ['$resource',
function($resource) {
return $resource('users', {}, {
update: {
method: 'PUT'
}
});
}
]);
angular resources by default have the following methods: get, save, query, remove, delete. unless otherwise specified, they will not pass the param in the url the way you need them to. In this case, you need to specify the remove method and ensure that the param gets passed in the url.
angular.module('users').factory('Users', ['$resource',
function($resource) {
return $resource('users', {}, {
update: {
method: 'PUT'
},
remove: {
method: 'DELETE',
url: 'users/:id',
params: {id: '#_id'}
}
});
}
]);
this assumes your user objects have an _id property, which is common in the mean stack. You should probably setup get save and update the same way.

Can someone give me an example on how I can call $resource directly?

In my code I have:
var EntityResource = $resource('/api/:entityType', {}, {
postEntity: { url: '/api/:entityType/', method: 'POST' },
getEntity: { url: '/api/:entityType/:entityId', method: 'GET' },
putEntity: { url: '/api/:entityType/:entityId', method: 'PUT' },
deleteEntity: { url: '/api/:entityType/:entityId', method: "DELETE" },
getEntities: { url: '/api/:entityType/:action/:id', method: 'GET', isArray: true },
});
Then I am using the following to get data:
getProjects: function (
entityType,
deptId) {
var deferred = $q.defer();
EntityResource.getEntities({
action: "GetProjects",
entityType: entityType,
deptId: deptId
},
function (resp) {
deferred.resolve(resp);
}
);
return deferred.promise;
},
and the following to call getProjects:
entityService.getProjects(
'Project',
$scope.option.selectedDept)
.then(function (result) {
$scope.grid.data = result;
}, function (result) {
$scope.grid.data = null;
});
I think the intermediate function getProjects is not needed and I would like to directly use $resource.
Can someone give me some advice on how I could do this? I looked at the AngularJS documentation for $resource and it's not very clear for me.
$resource calls by default return empty arrays and then fill them up when the response is received. As mentioned in documentation
It is important to realize that invoking a $resource object method
immediately returns an empty reference (object or array depending on
isArray). Once the data is returned from the server the existing
reference is populated with the actual data.
There are default 5 methods already defined on resource, get,save,query,remove,delete. You can directly call these rather than defining your own as you have done like postEntity, but the url template remains the same.
So once you define resource like this
var entityResource = $resource('/api/:entityType');
you can make calls like
var entity=entityResource.get({entityType:1},function(data) {
//The entity would be filled now
});
See the User example in documentation
If you want to return promise then you have to wrap the calls into your your service calls like you did for getProjects.
Update: Based on your comment, the definition could be
var entityResource = $resource('/api/:entityType/:action/:id')
Now if you do
entityResource.get({},function(){}) // The query is to /api
entityResource.get({entityType:'et'},function(){}) // The query is to /api/et
entityResource.get({entityType:'et',:action:'a'},function(){}) // The query is to /api/et/a
entityResource.get({entityType:'et',:action:'a',id:1},function(){}) // The query is to /api/et/a/1
Hope it helps.
$resource does expose $promise but it is on return values and subsequent calls.

Resources