Post Using Resource Causes Parameters to be Appended to URL - Angular JS - angularjs

I have the following service in my Angular App:
myAngularApp.factory('myFactory', function($resource, HOST){
return{
getThings: function(userId, userToken){
var connection = $resource(HOST + '/user/mypost/', {'Userid': userId, 'UserToken': userToken, 'Type': 'Read'}, {
save: {
method: 'POST'
}
});
var results = connection.save();
results.$promise.then(function(data){
results = data;
});
return results;
}
}
});
In one of my controllers, I call the above factory and its function using
myFactory.getThings($scope.someId, $scope.someToken);
When I look at the Network pane in developer tools, the POST request is sent with the correct query string parameters, but the URL is appended with the same parameters (a la GET request). How do I stop the parameters from being appended to my URL?

Try passing your parameters directly to your save() function and remove them from the URL parameters argument in your $resource constructor:
var connection = $resource(HOST + '/user/mypost/', {}, {save: {method: 'POST'}});
var params = {'Userid': userId, 'UserToken': userToken, 'Type': 'Read'};
var results = connection.save(params);

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.

How to pass data from $http.get to request body in angular

I am using express and angular for my app.
Suppose I have the following factory:
angular.module('LiveAPP.factory',[])
.factory('dataFactory', ['$http', dataFactory])
function dataFactory($http){
var dataFactory = {};
dataFactory.checkDb = function(){
return $http({
method: 'GET',
url: '/artistsearch',
data: "Need this data to go to the request body"
})
}
return dataFacory;
}
And on the server side I have:
app.js
app.get('/artistsearch',dbhelpers.checkDbArtist)
dbhelpers.js
exports.checkDbArtist = function(req,res,next){
var newArtist = req.body;
}
For some reason when checkDb is invoked my get request is not passing on data into my req.body in checkDbArtist. My request body evaluates to {}. Anyone have any idea why?

AngularJS factory. I need to call a method in a factory passing in a parameter then I need to retrieve the result from a different controller

I am new to AngularJS. I am building an email front-end as a college project.
I have an inbox view that retrieves emails from a json file. It works as expected by making this call: $scope.emails = InboxService.query();.
When the user clicks on an email they are redirected to a new page where I want to view the email, also from a json file (for testing only).
The controller:
app.controller('InboxController', function ($scope, $location, InboxService, EmailService) {
//Make call to email by id
$scope.viewEmail = function(emailId)
{
//DOES NOT WORK
EmailService.find({id: emailId});
$location.path('inbox/email/' + emailId);
};
//Make call to inbox
$scope.emails = InboxService.query();
});
When the user clicks on an email I want to use the id to retrieve another json file and pass it to a separate controller for a new page.
This is my EmailController:
app.controller('EmailController', function ($scope, InboxService, EmailService) {
$scope.emails = {};
//DOES NOT WORK
EmailService.getEmail(function(response){
$scope.emails.email = response;
});
});
This is the email service: DOES NOT WORK
app.factory('EmailService', function ($resource) {
var thisEmail = {};
thisEmail.find = function () {
thisEmail = $resource('json/message/:id.json', {}, {
get: {method: 'GET', params: {id: '#id'}}
})
},
thisEmail.getEmail = function () {
return thisEmail;
};
return thisEmail;
});
The service does not do what i want. I want to retrieve a json file using an id, then be able to access that file in the EmailController.
Try:
app.factory('EmailService', ['$resource',function ($resource) {
return $resource('json/message/:id.json', {}, {
get: {method: 'GET', params: {id: '#id'}}
});
}]);
In your controller:
EmailService.get({id:emailId});
You should use the built in state provider https://docs.angularjs.org/api/ngRoute/service/$route
or https://github.com/angular-ui/ui-router/wiki instead of directly working with the location hash.

angularjs resource limit changes after first call

Problem description
Im using the angular resource to get data from my server. I've extended it a bit to make sure all of my resources have security headers.
Problem is that on the second get request and on, my get requests are sent with limit=0, and only the first get request is sent correctly (with limit=12).
Code part
This is my base resource factory (for making sure all resource contain the keys and everything):
app.factory('SecuredFactory', function($resource){
var DEFAULT_ACTIONS = {
'get': {method:'GET'},
'query': {method:'GET', isArray:true},
};
var DEFAULT_PARAMS = {
'limit': 12,
'format': 'json'
};
for(var key in DEFAULT_ACTIONS){
DEFAULT_ACTIONS[key]['headers'] = <headers object>;
}
var securedResource = function(url, paramDefaults, actions){
for (var attrname in actions) {
DEFAULT_ACTIONS[attrname] = actions[attrname];
}
for (var attrname in paramDefaults) {
DEFAULT_PARAMS[attrname] = paramDefaults[attrname];
}
var defaultResource = $resource(url, DEFAULT_PARAMS, DEFAULT_ACTIONS);
return defaultResource;
};
return securedResource;
});
And this is an example of how I creat a specific factory out of the secured one:
app.factory('QuestionFactory', function(SecuredFactory, Constants){
var url = Constants.SERVER_URL + 'question/';
var Task = SecuredFactory(url);
return Task;
});
And this is finally how I use it, for example:
// filtering example (not important for this matter):
var filtering = {author: "Daniel"};
var contents = [];
var resource = QuestionFactory;
resource.get(filtering, function (res) {
// success fetching
$scope.contents = $scope.contents.concat(res['objects']);
}
// failed fetching
, function (err) {
}
);
The requests
first request:
question?format=json&limit=12&offset=0
second request and on:
question?format=json&limit=0&offset=0
My problem was that the DEFAULT_PARAMS variable was declared as global. I didn't realize that invoking the secured factory with {limit: 0} will override the global, therefore changing the limit to 0 for ALL of my resources.
Changing the securedFactory to a service and moving the "globals" into the returned function solved it. Had to add new ofcourse before every securedService call.

Angular.js delete resource with parameter

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.

Resources