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 }
});
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.
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.
I have a $http service in angular js which has a cache enable for it. When first time load the app service gets call and get cache. Now when i call the service anywhere from the same page the data comes from cache but when i change the page route and again call the service from another page the data come from server(i am just changing the route not refreshing the page)
Edit =>
Code was working !! On route the data also came from cache but it took more time as there are few other call as. It just took more time then i accepted the cache to respond .If i call same from any click event then it will take 2ms to 3ms
here is my service
commonServicesModule.service('getDetails', ['$http', 'urlc',
function($http, urlc) {
return {
consumer: {
profile: function(id) {
return $http({
url: urlc.details.consumer.profile,
cache: true,
params: {
'consumer_id': id,
'hello': id,
},
method: 'GET',
}).success(function(result) {
return result;
});
},
}
}
}
])
Call from controller :
start = new Date().getTime();
/*get user information */
getDetails.consumer.profile('1').then(function(results) {
console.log('time taken for request form listCtrl ' + (new Date().getTime() - start) + 'ms');
});
when i call this from anywhere else after route it take the same time.
Try moving the consumer object into the body of the function, and return a reference to it, like so:
commonServicesModule.service('getDetails', ['$http', 'urlc', function($http, urlc) {
var getConsumer = {
profile: function(id) {
return $http({
url: urlc.details.consumer.profile,
cache: true,
params: {
'consumer_id': id,
'hello': id,
},
method: 'GET',
}).success(function(result) {
return result;
});
}
};
return { consumer: getConsumer };
}]);
I'm implementing my own API-Token system into my AngularJS-Laravel project, so the API-Token is sent over $http using headers. The thing is, when a user logs in, it sets the API token in the API factory, but the $resource doesn't get updated.
myApp.factory('Api', ['$resource', '$http', '$cookies',function($resource, $http, $cookies) {
var baseURL = 'an api url';
var APIToken = $cookies.token;
return {
SetToken: function(token) {
APIToken = token;
console.log(APIToken);
},
Authenticator: function(data,callback) {
$http({
url: baseURL + 'auth',
method: "GET",
params: data
}).success(callback);
},
Authors: $resource(baseURL + "journalists/:id", {id: '#id'}, {
update: {
method:'PUT',
headers: { 'API-Token': APIToken }
},
query: {
method:'GET',
isArray: true,
headers: { 'API-Token': APIToken }
}
}),
};
}]);
The most interesting part is the headers: { 'API-Token': APIToken } part. The problem is that when SetToken is called, the headers won't get updated. Is there any way around this? Am I using the wrong function for this?
Your $resource object is created and setup only once when it is called. It doesn't access the APIToken variable every time you make a call to one of its functions. In order to make the code above work, you would have to call SetToken() before you call Authors() because once you call Authors(), the $resource object is created and will use the value of APIToken at that moment. I don't know of any way to do what you want and still use the $resource service. You might have to just use the $http service directly, like you're doing for your Authenticator function.
Authors: {
update: function(obj){
$http({
url: baseURL + 'journalists/' + obj.id,
method: "PUT",
params: obj
});
},
query: function(obj){
$http({
url: baseURL + 'journalists/' + obj.id,
method: "GET",
params: obj
});
},
})
Or something like that. Hope that helps.
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