Reputation: 1904
I am using $resource and caching the results of get requests. My problem is that, after post requests, the cache is not being invalidated.
Here is the return value from the service:
return $resource('http://url.com/api/url/:id', {}, {
'query' : {
method : 'GET',
isArray:true,
cache : true
},
'get' : {
method : 'GET',
cache : false
}
})
Here is the save method I am using inside my controller. As you can see, I'm using the callback on the post request to recalculate the query/list of nouns.
var newNoun = new Noun($scope.noun);
newNoun.$save(function(x) {
$scope.nouns = Noun.query();
});
I would like to invalidate the cache after calling post or another non-get method. How could I do this? Is this already built into $resource or do I need to implement it on my own?
Upvotes: 18
Views: 7381
Reputation: 48212
$resource
is using the default cache for $http
.
You can access it using: $cacheFactory.get('$http')
You can remove a key value pair, using the returned caches remove({string} key)
method.
E.g.:
var key = '...the key you want to remove, e.g. `/nouns/5`...';
$cacheFactory.get('$http').remove(key);
Upvotes: 1
Reputation: 1037
While @runTarm's answer above is great, it does not allow actions to be easily customized from the inheriting service, e.g. the following would not be possible:
app.factory('Steps', function (CachedResource) {
return CachedResource('/steps/:stepId', {}, {
save: { method: 'POST', params: { stepId: '@stepId' } }
});
});
In this case, this definition of save
would be replaced by the one present in CachedResource
.
But it can be fixed easily from Angular 1.4 by replacing
actions = angular.extend({}, actions, {
with
actions = angular.merge({}, actions, {
so that both objects are deep-merged.
In the above scenario, action options defined in CachedResource would be preferred over custom configuration in inheriting services. To fix that, switch the order of arguments passed to merge
:
actions = angular.merge({}, { /* default options get, query, etc. */ }, actions);
With this solution, the following will work as expected (i.e. use DESTROY
instead of default DELETE
when calling remove
):
app.factory('Steps', function (CachedResource) {
return CachedResource('/steps/:stepId', {}, {
remove: { method: 'DESTROY' }
});
});
Upvotes: 5
Reputation: 11547
You could create a wrapper service to do the caching like you want, for example:
app.factory('cachedResource', function ($resource, $cacheFactory) {
var cache = $cacheFactory('resourceCache');
var interceptor = {
response: function (response) {
cache.remove(response.config.url);
console.log('cache removed', response.config.url);
return response;
}
};
return function (url, paramDefaults, actions, options) {
actions = angular.extend({}, actions, {
'get': { method: 'GET', cache: cache },
'query': { method: 'GET', cache: cache, isArray: true },
'save': { method: 'POST', interceptor: interceptor },
'remove': { method: 'DELETE', interceptor: interceptor },
'delete': { method: 'DELETE', interceptor: interceptor },
});
return $resource(url, paramDefaults, actions, options);
};
});
Then replace any $resource
with cachedResource
.
Example plunker: http://plnkr.co/edit/lIQw4uogcoMpcuHTWy2U?p=preview
Upvotes: 29