Very simple scenario:
Code:
$.ajax({
type: "GET/POST",
url: 'http://somewhere.net/',
data: data,
beforeSend: '', // custom property
}).done().fail();
Basically I am looking for a legit way to modify beforeSend within Angular factory service. Please refer to what I have:
myApp.factory('GetBalance', ['$resource', function ($resource) {
return $resource('/Service/GetBalance', {}, {
query: { method: 'GET', params: {}, }, isArray: true,
});
}]);
Here I am using AngularJs services api problem is the documentation is not very helpful towards what I am trying to achieve.
If you want custom headers to be attached, you can do like this.
myApp.factory('GetBalance', ['$resource', function ($resource) {
return $resource('/Service/GetBalance', {}, {
query: { method: 'GET', params: {}, headers: { 'beforeSend': '' } }, isArray: true,
});
}]);
You might be interested in requestInterceptors, especially on the addFullRequestInterceptor method which has the following parameters:
It can return an object with any (or all) of following properties:
headers: The headers to send
params: The request parameters to send
element: The element to send
httpConfig: The httpConfig to call with
Solution sugested by #Thalaivar should have worked according to Angular docs but for whatever reason it just wouldn't work in my specific use case.
Here I provide an alternative solution that worked out for me as follows:
myApp.config(['$provide', '$httpProvider', function ($provide, $httpProvider) {
// Setup request headers
$httpProvider.defaults.headers.common['modId'] = 1; // dynamic var
$httpProvider.defaults.headers.common['pageId'] = 2; // dynamic var
$httpProvider.defaults.headers.common['token'] = 'xyz'; // dynamic var
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
});
I know that headed values are hard coded in my example but in reality things change from page to page so those values are actually dynamically retrieved.
Again if you are using $http based services then you should not need to do this.
Related
I am currently using angular-hateoas (https://github.com/jmarquis/angular-hateoas). I would like to add specific interceptors to the query() and get() functions of the resource created in HateoasInterface. I have been looking for ways to do it, but not been successful.
I thought it could be done by adding it like this:
var someResource = someService.resource('someresource');
someResource.query.interceptors = {
response: function (data) {
// do something data
return data
},
responseError: function (error) {
// do something with error
return $q.reject(error);
}
};
but that gives me:
TypeError: Attempted to assign to readonly property.
I might need to use $decorator, but I have no experience with that, and I have seen no example for adding specific interceptors to specific resource objects.
I don't really want to use $httpProvider.interceptors, since I don't want the interceptor to work on all resources.
The only thing I can currently think of, is configuring HateoasInterfaceProvider with specificly named functions that contain the specific interceptors.
angular.module('myModule')
.config(HateoasInterfaceConfig);
HateoasInterfaceConfig.$inject = ['HateoasInterfaceProvider'];
function HateoasInterfaceConfig(HateoasInterfaceProvider) {
HateoasInterfaceProvider.setHttpMethods({
get: {
method: 'GET',
isArray: false
},
getSomeResource: {
method: 'GET',
isArray: false,
interceptors: {
response: someResponseFunc,
responseError: someErrorFunc
}
},
update: {
method: 'POST',
},
query: {
method: 'GET',
isArray: true
}
querySomeResource: {
method: 'GET',
isArray: true,
interceptors: {
response: function(data) {
// do something with data
return data;
},
responseError: function (error) {
//do something with error
return $q.reject(error);
}
}
});
HateoasInterfaceProvider.setLinksKey('_links');
}
but I prefer not to do it like that.
Figured it out.
When calling a resource, params and actions can be passed.
So like:
someServiceResult.resource('someresource',{},{get: {method: 'GET',...,
interceptor: { response: responseInterceptorFunc, ...}}})
Still not really the preferred solution, but when wrapped in a function in a service, acceptible.
I would like to have a solution that allows changing the interceptor definition for the Resource object created with:
someServiceResult.resource('someresource')
but I currently don't have time for figuring that out.
I have a factory like this:
angular
.module('app')
.factory('RepositoriesService', RepositoriesService);
function RepositoriesService($resource) {
var persistentData = null;
var data = $resource('http://xxxxxxx.co.uk/:id', { id: '#id' }, {
update: { method: 'PUT' },
query: { isArray: false }
});
return data;
}
In my controller, I can get the data like this:
RepositoriesService.query();
Now, I want persistent data in the factory. So the first time the query is made, the data returned should save to the persistentData variable. Subsequent query requests to the factory should return the persistentData value rather than making a new API request for data. I know how to do this easily with $http but is it possible with ngResource?
According to the docs you can use the cache option:
cache – {boolean|Cache} – If true, a default $http cache will be used to cache the GET request, otherwise if a cache instance built with $cacheFactory, this cache will be used for caching.
To cache the query requests in your case:
var data = $resource('http://xxxxxxx.co.uk/:id', { id: '#id' }, {
update: { method: 'PUT' },
query: { isArray: false, cache: true }
});
EDIT:
To have a better control over the cache, pass your own cache object built with the $cacheFactory service:
// now you can use this object in your service
// to control the cache behaviour, like clean it after a while
var myCache = $cacheFactory('RepositoryService');
var data = $resource('http://xxxxxxx.co.uk/:id', { id: '#id' }, {
update: { method: 'PUT' },
query: { isArray: false, cache: myCache }
});
I have an html template that displays data from an Angular factory. The problem is that the factory's get method performs call to the backend only when the page is loaded for the first time. When repeatedly opening the page I only see results from the first call to the backend. It looks like the factory somehow caches the results.
With using Chrome debug tools I see that Angular makes GET requests with the same resource id on each page load.
This is the factory definition:
.factory('Company', ['$resource', '$routeParams', function ($resource, $routeParams) {
return $resource('/companies/getCompany/:companyId', {}, {
get: {
method: 'GET',
url: '/companies/getCompany/:companyId',
params: {
'companyId': $routeParams.companyId
}
},
save: {
method: 'POST',
url: '/companies/updateCompany'
},
insert: {
method: 'POST',
url: '/companies/createNewCompany'
}
});
}])
This is the controller code
.controller('MyController', ['$scope', '$location', 'Company',
function ($scope, $location, Company) {
Company.get(function (data) {
$scope.company = data;
});
}]);
I'm using ng-click to open the page
<tr ng-repeat="company in companies"
ng-click="redirectToCompanyForm(company.id)">
$scope.redirectToCompanyForm = function (companyId) {
$location.url('/updateCompany/' + companyId);
}
I set a breakpoint on the factory - app pauses only the first time when I access the page.
Why is my factory called only once and how can I solve this?
From the Angular docs:
Note: All services in Angular are singletons. That means that the injector uses each recipe at most once to create the object. The injector then caches the reference for all future needs.
So you are right, all services are only created once and then cached by Angular.
Edit: better answer for your situation below:
$resource caching
You can disable caching the resource by adding the options to the $resource call:
return $resource('/companies/getCompany/:companyId', {}, {
get: {
method: 'GET',
params: {
'companyId': $routeParams.companyId
},
cache: false // THIS LINE
}
}
Edit 2: according to the docs, the first parameter of $resource is not optional and must be an url.
Maybe you can use low level $http methods in your controller.
$resource is a fantastic utility but in your case you don't want persist the data.
Try the $http.get method..
Or try the query() method.
$scope.myData = DataFactory.query();
Finally fixed the issue. Factory use was incorrect. This is the factory module
.factory('Company', ['$resource', function ($resource) {
return $resource('/companies/getCompany/:id', null, {
save: {
method: 'POST',
url: '/companies/updateCompany'
},
insert: {
method: 'POST',
url: '/companies/createNewCompany'
}
});
}])
And this is how the factory should be called
Company.get({id: $routeParams.companyId}, function (data) {
$scope.company = data;
});
Now the correct data is shown everytime the page is loaded.
I'm using angularjs 1.2.0 with $resource. I would like to have some PUT/POST instance actions that doesn't send the whole object to the server but only some fields and in some cases totally no data.
Is it possible? I searched everywhere but couldn't find anything
UPDATE:
It also happens with DELETE requests:
Given this code:
group.$deleteChatMessage({messageId: message.id}, function(){
var i = _.indexOf(group.chat, message);
if(i !== -1) group.chat.splice(i, 1);
});
The request is this:
See how the whole model is sent (under "Request Payload").
This is the resource:
var Group = $resource(API_URL + '/api/v1/groups/:gid',
{gid:'#_id', messageId: '#_messageId'},
{
deleteChatMessage: {method: "DELETE", url: API_URL + '/api/v1/groups/:gid/chat/:messageId'},
});
This works for me:
$resource(SERVER_URL + 'profile.json',
{},
{
changePassword :
{
method : 'POST',
url : SERVER_URL + 'profile/changePassword.json',
// Don't sent request body
transformRequest : function(data, headersGetter)
{
return '';
}
}
});
You could customise exaclty what is sent to the server by implementing your own code in the transformRequest function. In my example I was adding a new function to the REST client, but you can also overwrite existing functions. Note that 'transformRequest' is only available in version 1.1+
You can use $http for that specifically. However, I have one case I use for a project that might help. Also my example is returning an array from the server but you can change that.
In my service:
app.factory('mySearch', ['$resource', function($resource) {
return $resource('/api/items/:action', {}, {
search: { method: 'POST', isArray: true,
params: { action: 'search' }
}
});
}
]);
In my Controller:
I can build up custom params to post to server or if its only two fields I need from a table row the user selects.
var one = "field_one";
var two = "field_two";
$scope.search({one: one, two: two});
Then I can post those through an event and pass the custom params
$scope.search = function(customParams) {
mySearch.search({query: customParams}, function(data) {
$scope.items = data;
}, function(response) {
console.log("Error: " + response.status);
})
};
Hopefully this was some help. Let me know if this is close to what your looking for and I can help more.
POST
DELETE
I have some old code that is making an AJAX POST request through jQuery's post method and looks something like this:
$.post("/foo/bar", requestData,
function(responseData)
{
//do stuff with response
}
requestData is just a javascript object with some basic string properties.
I'm in the process of moving our stuff over to use Angular, and I want to replace this call with $http.post. I came up with the following:
$http.post("/foo/bar", requestData).success(
function(responseData) {
//do stuff with response
}
});
When I did this, I got a 500 error response from the server. Using Firebug, I found that this sent the request body like this:
{"param1":"value1","param2":"value2","param3":"value3"}
The successful jQuery $.post sends the body like this:
param1=value1¶m2=value2¶m3=value3
The endpoint I am hitting is expecting request parameters and not JSON. So, my question is is there anyway to tell $http.post to send up the javascript object as request parameters instead of JSON? Yes, I know I could construct the string myself from the object, but I want to know if Angular provides anything for this out of the box.
I think the params config parameter won't work here since it adds the string to the url instead of the body but to add to what Infeligo suggested here is an example of the global override of a default transform (using jQuery param as an example to convert the data to param string).
Set up global transformRequest function:
var app = angular.module('myApp');
app.config(function ($httpProvider) {
$httpProvider.defaults.transformRequest = function(data){
if (data === undefined) {
return data;
}
return $.param(data);
}
});
That way all calls to $http.post will automatically transform the body to the same param format used by the jQuery $.post call.
Note you may also want to set the Content-Type header per call or globally like this:
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
Sample non-global transformRequest per call:
var transform = function(data){
return $.param(data);
}
$http.post("/foo/bar", requestData, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
transformRequest: transform
}).success(function(responseData) {
//do stuff with response
});
If using Angular >= 1.4, here's the cleanest solution I've found that doesn't rely on anything custom or external:
angular.module('yourModule')
.config(function ($httpProvider, $httpParamSerializerJQLikeProvider){
$httpProvider.defaults.transformRequest.unshift($httpParamSerializerJQLikeProvider.$get());
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
});
And then you can do this anywhere in your app:
$http({
method: 'POST',
url: '/requesturl',
data: {
param1: 'value1',
param2: 'value2'
}
});
And it will correctly serialize the data as param1=value1¶m2=value2 and send it to /requesturl with the application/x-www-form-urlencoded; charset=utf-8 Content-Type header as it's normally expected with POST requests on endpoints.
From AngularJS documentation:
params – {Object.} – Map of strings or objects which
will be turned to ?key1=value1&key2=value2 after the url. If the
value is not a string, it will be JSONified.
So, provide string as parameters. If you don't want that, then use transformations. Again, from the documentation:
To override these transformation locally, specify transform functions
as transformRequest and/or transformResponse properties of the config
object. To globally override the default transforms, override the
$httpProvider.defaults.transformRequest and
$httpProvider.defaults.transformResponse properties of the
$httpProvider.
Refer to documentation for more details.
Use jQuery's $.param function to serialize the JSON data in requestData.
In short, using similar code as yours:
$http.post("/foo/bar",
$.param(requestData),
{
headers:
{
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
}
).success(
function(responseData) {
//do stuff with response
}
});
For using this, you have to include jQuery in your page along with AngularJS.
Note that as of Angular 1.4, you can serialize the form data without using jQuery.
In the app.js:
module.run(function($http, $httpParamSerializerJQLike) {
$http.defaults.transformRequest.unshift($httpParamSerializerJQLike);
});
Then in your controller:
$http({
method: 'POST',
url: myUrl',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: myData
});
This might be a bit of a hack, but I avoided the issue and converted the json into PHP's POST array on the server side:
$_POST = json_decode(file_get_contents('php://input'), true);
I have problems as well with setting custom http authentication because $resource cache the request.
To make it work you have to overwrite the existing headers by doing this
var transformRequest = function(data, headersGetter){
var headers = headersGetter();
headers['Authorization'] = 'WSSE profile="UsernameToken"';
headers['X-WSSE'] = 'UsernameToken ' + nonce
headers['Content-Type'] = 'application/json';
};
return $resource(
url,
{
},
{
query: {
method: 'POST',
url: apiURL + '/profile',
transformRequest: transformRequest,
params: {userId: '#userId'}
},
}
);
I hope I was able to help someone. It took me 3 days to figure this one out.
Modify the default headers:
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8";
Then use JQuery's $.param method:
var payload = $.param({key: value});
$http.post(targetURL, payload);
.controller('pieChartController', ['$scope', '$http', '$httpParamSerializerJQLike', function($scope, $http, $httpParamSerializerJQLike) {
var data = {
TimeStamp : "2016-04-25 12:50:00"
};
$http({
method: 'POST',
url: 'serverutilizationreport',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
data: $httpParamSerializerJQLike(data),
}).success(function () {});
}
]);
Quick adjustment - for those of you having trouble with the global configuration of the transformRequest function, here's the snippet i'm using to get rid of the Cannot read property 'jquery' of undefined error:
$httpProvider.defaults.transformRequest = function(data) {
return data != undefined ? $.param(data) : null;
}
You can also solve this problem without changing code in server, changing header in $http.post call and use $_POST the regular way. Explained here: http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/
I found many times problematic behavior of this whole. I used it from express (without typings) and the bodyParser (with the dt~body-parser typings).
I didn't try to upload a file, instead simply to interpret a JSON given in a post string.
The request.body was simply an empty json ({}).
After a lot of investigation finally this worked for me:
import { json } from 'body-parser';
...
app.use(json()); <-- should be defined before the first POST handler!
It may be also important to give the application/json content type in the request string from the client side.
Syntax for AngularJS v1.4.8 + (v1.5.0)
$http.post(url, data, config)
.then(
function (response) {
// success callback
},
function (response) {
// failure callback
}
);
Eg:
var url = "http://example.com";
var data = {
"param1": "value1",
"param2": "value2",
"param3": "value3"
};
var config = {
headers: {
'Content-Type': "application/json"
}
};
$http.post(url, data, config)
.then(
function (response) {
// success callback
},
function (response) {
// failure callback
}
);