Angular $resource: object id lost using POST with custom methods - angularjs

I want to use a custom method in my Foo Factory with a POST call. When I call it as a GET request, it works, but it's deny by my api because it doesn't allow GET for that method.
Request: GET /api/foo/272ee694-b517-4012-b740-98f76973091d/custom_method/ 405
When I change the method to POST (in the angular factory), the object id disapears:
Request: OPTIONS /api/foo/custom_method/ 174
Request: POST /api/foo/custom_method/ 405
Note that this time an OPTION request is made before without the id.
My factory looks like:
appService.factory('foo', ['$resource', 'appConfig',
function($resource, appConfig){
var api_path = appConfig.api_path;
return $resource(api_path + 'foos/:fooId/', {fooId:'#id'},{
query: {
method: 'GET',
isArray: false
},
customMethod: {
method: 'POST',
url: api_path + 'foos/:fooId/custom_method/'
}
});
}]);
And my controler:
$scope.foo = foo.get({fooId: $routeParams.fooId});
$scope.customMethod = function() {
foo.customMethod({fooId:$scope.foo.id});
}
Anyone could help me? Thank you in advance

So, I found the solution. In the controller, just call custom_method from the object with a $. Like this:
$scope.foo.$custom_method();
You can also omit to pass the id because $resource get it from the object by default.

Related

how to have angularJS post data to MVC controller which redirects to a view

I am posting some data to an MVC action method using AngularJS. This action method will either show its backing view or redirect to another page. Currently all that is happening is the data is getting posted but the redirect is not happening via MVC. I am getting this done using angular's window.location method. I want to know if there is a better way or if I need to post differently using Angular.
On page A I have angular scripts posting data to page B like below:
serviceDataFactory.POST('http://localhost:1234/home/B', someData, pageConfig).then(function () {
//on success
window.location = 'http://localhost:1234/home/Index';
},
function() {
//on error
window.location = 'http://localhost:1234/home/B';
});
This is my service factory
app.factory('serviceFactory', function($http, $q) {
var service = {};
//POST
service.POST = function (url, postData, conf) {
var d = $q.defer();
$http({
method: 'POST',
url: url,
data: postData,
config: conf
}).success(function(data) {
d.resolve(data);
}).error(function(error) {
d.reject(error);
});
return d.promise;
}
return service;
}
);
On Page B I want to redirect to another page. This is my page B in MVC
[HttpPost]
public ActionResult B(string someData)
{
//recieve string someData and perform some logic based on it
.
.
.
if(boolCondition)
return RedirectToAction("Index", "Home");
else
return View();
}
Here once Angular posts to the action method B, it executes all the code all the way till the if(boolCondition) statement. Since I am unable to have that redirect affected via MVC, I do that in Angular itself using the success or error block that the promise returns to.
I want to know if there is a better way to do this or if I am doing something wrong here or if this is the only acceptable way. How do I get angular to hand-off to the MVC action method and let further redirects continue from there only?
You should not use the .success() / .error() pattern with $http, because this has been deprecated. Instead, use then() with two arguments, the first argument being the success function and the second being the error function.
The $http legacy promise methods success and error have been
deprecated. Use the standard then method instead. If
$httpProvider.useLegacyPromiseExtensions is set to false then these
methods will throw $http/legacy error.
You do not need to promisify the result of $http, because $http returns a promise. Just return $http from your service.
app.factory('serviceFactory', function($http, $q) {
var service = {};
//POST
service.POST = function (url, postData, conf) {
return $http({
method: 'POST',
url: url,
data: postData,
config: conf
});
}
return service;
});
Your Page A controller will work the same as before with this new simplified code. At the server, be sure to emit a 500 http status code in cases where you want to trigger the
function() {
//on error
window.location = 'http://localhost:1234/home/B';
}
to run. The 500 in the headers of the response will cause the AngularJS promise to run the second function in your controller.

AngularJS $resource Headers POST

I would like to know how to pass headers to AngularJS $resource method
Here is the factory method
.factory('DataRepository', function ($resource) {
return $resource(serviceUrlPrefix + '/api/v1/AppList/:id', { id: '#id' }, { 'query': { method: 'GET', isArray: false }, 'update': { method: 'PUT', AppList: '#req', headers: { 'X-Requested-With': 'XmlHttpRequest' } } });
});
Here is the call to the dataRepository
dataRepository.update({ id: req[uniqueIDColumn] }, req, function (data) {
},
function (error) {
});
This code works fine. But i have few queries
Question 1:
Rather than specifying the headers in the factory method , how can i specify it in the call to the factory method? I tried few methods but it didnt work out.
Question 2:
I specified the header in the update method in the factory. When i perform "Save" using that factory, that header has been taken by default. But i have specified it explicitly for PUT method. Right? Why and how?
Question 3:
If i would like to specify the header for the particular factory in common for all Http methods, what is the way to do it?
Question 4:
What is the nomenclature for passing the parameters and the significance of "#" symbol before parameter and also in the below part, AppList is the parameter name used in the WebAPI, is it mandatory that it should match the parameter name in the WebAPI method, if its not matching, its not working:(
AppList: '#req'
I'm afraid we don't use $resource, but it does depend on $http. We configure the header with the below. Not sure about the rest of your questions.
I will say that we also do not use $http directly. We created our own "requestHelper" service that we inject everywhere. That allows us to inject things before making calls to $http as well as catch the response before passing the result on to the real caller. Helps with common error handling.
Configure headers for $http:
module.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
}]);

How to retrieve objects from rest url with multiple parameters using angular

How can i create a factory that can retrieve data from
/rest/company/:companyid/employee/:id
when i use this url in the factory I get an error: Unknown provider companyidProvider
Thank you,
Kyle
Service:
app.factory('EmployeeByCompany', function ($resource,companyid) {
return $resource('app/rest/company/:companyid/employee/:id', {}, {
'query': { method: 'GET', isArray: true},
'get': { method: 'GET'}
});
});
I'm guessing the error is from having the companyid as a parameter with $resource. What is the right way for a service to call this url?
If you are learning or geting started, try Restangular https://github.com/mgonto/restangular

AngularJS $resource save() causes HTTP Error 415 (Unsupported Media Type)

I am using Angular 1.2-RC2 (also tried 1.0.8 and 1.1.x) and the ngResource module. The backend is a Spring WebMVC application.
angular.module("dox", ['ngResource'])
.controller('SettingsController', function ($scope, Settings) {
$scope.settings = Settings.query();
$scope.save = function () {
Settings.save();
};
})
.factory('Settings', function ($resource) {
return $resource('/api/v1/settings/:settingId', {settingId: '#id'}, {
'save': {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
}
});
});
Whenever the save() method on the Settings class gets called the frontend receives a HTTP 415 (Unsupported media type). The reason is that AngularJS send the POST request using the following content type:
Content type: text/plain;charset=UTF-8
but the backend expects
Content type: application/json;charset=UTF-8
According the API docs it should be possible to override the header but my settings are somehow ignored. I seems that this is a common problem and as a workaround there are many recommendation to use $http.post instead of $resource.
Can you give me any hint how to solve this content type problem using the $resource service?
Please find the backend controller code here.
First, you're overriding a built-in $save method, so you can just omit the save: part (see source code). If you do define additional HTTP methods that aren't built-in, you can update the $httpProvider like so (this is to add the patch method):
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.headers.patch = {
'Content-Type': 'application/json;charset=utf-8'
}
}]);
Kevin Stone pushed me to the right direction. Thank you!
Since query() returns an array and save() is meant to save only one item of that array at the same time I had to reimplement the save() stuff differently.
$scope.save = function () {
angular.forEach($scope.settings, function (value, key) {
value.$save();
});
};
Done! Again thank you for your hints and help

ng-resource url parameter does not work

$resource is not correctly passing along a url parameter when making a PUT request, via custom action.
This is my service creating the resource.
.factory('cartItemsService', ['$resource', function($resource) {
return $resource('/api/cart/:cartId/items/', {format: 'json'}, {
get: {method: 'GET', isArray: true},
update: {method: 'PUT', isArray: true},
});
}])
In my controller I'm trying to update the list of items like this. Note that $scope.cart.id exists and is correct (in this case 1)
$scope.cartItems = cartItemsService.update({cartId: $scope.cart.id});
However the request URL is: /api/cart/items/ but I'm expecting /api/cart/1/items/. This works fine if I do .get({cartId: <some_id>}) but doesn't seem to work for update.
EDIT: Angular version 1.1.5
In the end this was due to the request headers I was setting before making the request.
I was attempting to set put headers like such:
$http.defaults.headers.put['X-CSRFToken'] = $cookies.csrftoken;
This is what caused the request url to be incorrectly formatted.
Changed it to set the post header instead, and it worked.
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;

Resources