Using custom cache object with AngularJS $http
Hello
At work, I’ve been bitten by the way AngularJS handles cache by default when using $https service. This post will show a simple way to improve cache handling with $http service.
The service I’m working on must perform the followings tasks:
- retrieve data from a remote server.
- save data to the same server.
- retrieve the saved data and some extra information generated by the server to update a UI
At first, I’ve naively used $http.get cache parameter to enable or disable caching using a sequence like:
- $http.get(url, {cache: true} )
- $http.post(url)
- $http.get(url, {cache: false})
- $http.get(url, {cache: true})
Let’s say the calls above use the following data:
- $http.get(url, {cache: true}) returns “foo”
- $http.post(url) stores “bar”
- $http.get(url, {cache: false}) returns “bar”
I expected the next call $http.get(url, {cache: false}) to return “bar”. But no, I got “foo”, i.e. the obsolete data.
Turns out that cache object is completely left alone when {cache: false} is passed to $http.get.
ok. Fair enough. But this means that the value of the cache parameter should not change for a given URL. The default cache provided by $https cannot be cleared. (Well, actually, you can clear the cache under AngularJS’s hood, but that will probably not improve the readability of your code).
The naive approach does not work. Let’s try another solution by using a custom cache object as suggested by AngularJS doc. This cache object should be created by $cacheFactory service.
This cache object can then be passed to $http.get to be used as cache. When needed, the cache can be cleared. In the example above, the cache must be cleared after saving some data to the remote service.
There’s 2 possibilities to clear a cache:
- Completely flush the cache using removeAll() function.
- Clear the cache for the specific URL using remove(key) function. The only hitch is that the “key” used by $http is not documented.
So, we have to use the first solution and create a cache object for each API entry point:
angular.module('app').factory('myService', function ($http, $cacheFactory) { var myFooUrl = '/foo-rest-service'; // create cache object. The cache id must be unique var fooCache = $cacheFactory('myService.foo'); function getFooData () { return $http.get( myFooUrl, { cache: fooCache }); }; function saveFooData(data) { return $http.post( myFooUrl, { cache: fooCache }).then(function() { myCache.removeAll() ; }); } });
The code above ensures that:
- cached data for foo service is always consistent
- http get requests are not sent more than necessary
This simple approach has the following limitations:
- cache is not refreshed if the data on the server are updated by another client
- cache is flushed when only the browser page is reloaded
If you need more a more advance cache mechanism, you may want to check jmdobry’s angular cache project
All the best
Hi Dominique (had to google you on debian to find your 1st name).
I would like to thank you for you clear post on LWP, proxy, and https issues. I had been struggling with it for 3 days trying to understand what was going on. Thank you
Also, I am a unix sysadmin that programs in perl and python using VI and I have been usually doing programming jobs in php and JS. I dont like JS but I need to deal with it. What do you use to program in JS? I am the kind of guy who open an xterm with VI and another one with bash where I execute my script, and thats how I develop. Is there a similar way to develop in JS? I tried using VI and NODE.JS but JS in NODE is kinda different from within the browser.
Thanks for any advice, and congrats for being part of the debian team!!
p.s. plz delete the 1st post, I forgot to check the notification box
Hello Andre
Thanks for the nice words. I’m kinda old school and use emacs with js2-mode, js2-refactor and helm to edit JavaScript files. Currently I mostly work on AngularJS 1.2 and sometimes on node. I use emacs for both.
All the best