96

I have a simple User $resource that uses the default $http cache implementation like so:

factory('User', function($resource){
    return $resource(endpoint + '/user/current/:projectId', {},
        {get: 
            {
                cache: true,
                method: 'GET'
            }
        }
    );
})

This works very well, i.e. my server is only called once in my application, then the value is fetched from cache.

But I need to refresh the value from the server after a certain operation. Is there an easy way to do that?

Thanks.

Alexandre Bulté
  • 1,402
  • 1
  • 12
  • 14
  • 1
    I'm using unstable (1.1.5 but I think it's there since 1.1.2) **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the GET request, otherwise if a cache instance built with – Alexandre Bulté Jun 12 '13 at 07:50
  • 1
    i'm having similar problem but only when testing. how do i bust this thing at the browser level? – chovy Nov 30 '13 at 05:49

3 Answers3

119

Keep the boolean and get the $http cache:

var $httpDefaultCache = $cacheFactory.get('$http');

Then you can control it like any another cache made with $cacheFactory, a usage instance provided below:

$httpDefaultCache.remove(key);
// Where key is the relative URL of your resource (eg: /api/user/current/51a9020d91799f1e9b8db12f)
theunexpected1
  • 1,017
  • 11
  • 23
Anthonny
  • 1,591
  • 1
  • 9
  • 9
  • 53
    Perfect, thank you! Exactly what I was looking for. For those wondering, you can call $cacheFactory.get('$http').remove(key), with key being the relative URL of your resource (ex: /api/user/current/51a9020d91799f1e9b8db12f). – Alexandre Bulté Jun 12 '13 at 12:25
  • 2
    Actually I found that I needed to specify the full url along with any query parameters when calling remove(). Am I missing something here? – shangxiao Oct 17 '13 at 16:35
  • @shangxiao If the URL being cached contains query parameters, then yes, you will have to specify them in the `remove()` key. Relative URLs do work, though, at least in 1.2.9. – alalonde Jan 31 '14 at 18:04
  • 3
    I have dynamic query parameters. Is there a way to access the url from `$resource` factory? – suzanshakya Jul 28 '14 at 14:49
  • 1
    While this works. It may be more complexity than needed. A better solution would be if this was implemented: http://github.com/angular/angular.js/issues/9064 – KFunk Sep 13 '14 at 04:45
  • 6
    For me, $cacheFactory.get('$http').removeAll() did the trick, as I needed to clear all cached data. – S. Baggy Jun 01 '15 at 22:49
18

Instead of using a boolean argument in the cache property of each action you can pass on a cache instance created with $cacheFactory which you can have more control over (i.e. clear the cache).

Example usage:

app.factory('Todos', function($resource, $cacheFactory) {
    var cache = $cacheFactory('todo');
    return $resource(apiBaseUrl + '/todos/:id', { id: '@id' }, {
        'get': { method: 'GET', cache: cache  },
        'query': { method: 'GET', cache: cache, isArray: true }
    });
});
thorn0
  • 9,362
  • 3
  • 68
  • 96
Variant
  • 17,279
  • 4
  • 40
  • 65
6

I came across this thread looking for something similar, but found that $resource will manage the cache for you automatically, so there's no need to force the cache to be cleared.

The idea is that if you have a resource that you can query, that query response will be cached, but if you save something for that same resource, the previously cached data must be invalid, so it is cleared for you. It makes sense that it would work this way.

Here's some code I use to do this (you can ignore the possibly odd-looking factory creation part and pay attention to the "class" body).

'use strict';

sampleApp.players.$ng.factory('sampleApp.players.PlayerService', [
    '$log',
    '$resource',
    sampleApp.players.PlayerService = function ($log, $resource) {
        var service = {};

        $log.info('Creating player resource.');
        var Player = $resource('/api/players', {}, {query: {
            isArray: true,
            cache: true,
            method: 'GET'
        }});

        service.addPlayer = function(playerName) {
            $log.info('Saving a new player.');
            return new Player({name: playerName}).$save();
        };

        service.listPlayers = function () {
            $log.info('Fetching players.');
            return Player.query();
        };

        return service;
    }]);

If you call the listPlayers function several times, the first call makes a http get request and all subsequent calls are cached. If you call addPlayer though, a http post is performed as expected, and then the next call to listPlayers will perform a http get (not cached).

This keeps you out of the business of managing someone else's ($http) cache and trying to keep up with which url's are being used for requests and which are clearing caches at the right times.

I suppose the moral of the story here is to work with the library and all will be well... except for any bugs or incomplete features, but Angular doesn't have any of those ;)

p.s. This is all running on AngularJS 1.2.0.

user605331
  • 3,718
  • 4
  • 33
  • 60
  • 2
    Yes, I understand and acknowledge that in "normal" conditions the Angular resource knows how and when to invalidate the cache, and it works perfectly. But my use case was slightly different: I wanted to force a refresh because Angular had no way of knowing that a refresh was needed - the user object being modified outside the Angular app. – Alexandre Bulté Nov 11 '13 at 10:58
  • 3
    Can anyone point to where this is documented? I've read about this before on Stack Overflow, but cannot find any mention of it in the documentation. I've tried it as well in my app, but perhaps have done something wrong along the way... – Sunil D. Feb 19 '14 at 04:40
  • 1
    It does not appear however to work with $delete. The next call will pull from cache again and the deleted item will reappear. Can anyone confirm? – Lukus Apr 24 '14 at 21:32
  • This will not work ngResource DO NOT HANDLE cache invalidation go here for example : http://stackoverflow.com/questions/25117388/invalidate-resource-cache-after-post-request?lq=1 – HugoPoi Jun 15 '16 at 17:05