Skip to content

Instantly share code, notes, and snippets.

@drphrozen
Created November 19, 2012 14:52
Show Gist options
  • Save drphrozen/4111076 to your computer and use it in GitHub Desktop.
Save drphrozen/4111076 to your computer and use it in GitHub Desktop.
angular.module('LocalCacheModule', []).
factory('LocalCache', ['$q', '$log', function(q, log) {
var retrievers = {};
var ttls = {};
var localCache = {
retrieve: function(key, ready) {
var retriever = retrievers[key];
if (angular.isFunction(retriever)) {
retriever(function(data) {
localCache.put(key, data);
ready(data);
});
} else {
log.error("A function was not registered for the given cache key!");
}
},
get: function(key, readyCallback, forceUpdate) {
var item = { value: null };
if (!angular.isFunction(readyCallback)) {
readyCallback = angular.noop;
}
var tryGetItem = function() {
var tmp = localStorage.getItem(key);
if (tmp !== null) {
item = angular.fromJson(tmp);
}
return tmp !== null;
};
if (retrievers[key]) {
if (forceUpdate === true || !localCache.isAlive(key) || !tryGetItem()) {
// Force update or TTL expired
localCache.retrieve(key, function (data) {
angular.copy(data || {}, item);
readyCallback(data);
});
} else {
readyCallback(item);
}
return item;
} else {
item = localStorage.getItem(key);
return item === null ? null : angular.fromJson(item);
}
},
register: function(key, retrieve, ttl) {
if (!angular.isFunction(retrieve) || angular.isUndefined(ttl)) {
log.error('register must be called with a retrieve function and a valid ttl');
return;
}
localCache.registerRetriever(key, retrieve);
localCache.registerTtl(key, ttl);
},
registerTtl: function(key, ttl) {
ttls[key] = { ttl: ttl };
localCache.updateTimeout(key);
},
updateTimeout: function(key, tryUpdate) {
var ttlObj = ttls[key];
if (angular.isUndefined(ttlObj) && tryUpdate !== true) {
log.error('registerTtl was not called for ' + key);
return;
}
var ttl = ttlObj.ttl;
var timeout;
if (angular.isNumber(ttl)) {
timeout = new Date(ttl + +new Date);
} else if (angular.isString(ttl)) {
switch (ttl) {
case 'midnight':
var d = new Date;
d.setHours(0, 0, 0, 0);
timeout = d;
break;
default:
log.error('ttl is not a valid value: ' + ttl);
return;
}
} else {
log.error('ttl is not a valid value: ' + ttl);
return;
}
ttlObj.timeout = timeout;
},
isAlive: function(key) {
var ttlObj = ttls[key];
return angular.isUndefined(ttlObj) || ttlObj.timeout > +new Date;
},
registerRetriever: function(key, retrieve) {
retrievers[key] = retrieve;
},
unregister: function(key) {
delete retrievers[key];
delete ttls[key];
},
put: function(key, value) {
localStorage.setItem(key, angular.toJson(value));
localCache.updateTimeout(key, true);
},
remove: function(key) {
localStorage.removeItem(key);
}
};
return localCache;
}]).
factory('Cacheable', ['LocalCache', '$log', function (localCache, log) {
var CacheableFactory = function (key) {
if (!angular.isString(key)) {
log.error("key must be of type string!");
return undefined;
}
var obj = {};
angular.forEach(['get', 'put', 'remove', 'register', 'registerTtl', 'registerRetriever', 'updateTimeout', 'isAlive', 'unregister'], function (value) {
obj[value] = function () {
var args = Array.prototype.slice.call(arguments);
args.splice(0, 0, key);
localCache[value].apply(localCache[value], args);
};
});
return obj;
};
return CacheableFactory;
}]);
angular.module('MyApp', ['LocalCacheModule', 'ngResource']);
var MyController = function ($scope, Cacheable, $resource) {
var bar = Cacheable('bar');
// register() overrides previous registrations for this key
bar.register(function (callback) {
var response = resource('/foo/bar').get({}, function() {
callback(response);
})
}, 5000);
var baz = Cacheable('baz');
baz.register(function (callback) {
callback(+new Date);
}, 'midnight');
// Simple get, supports all datatypes
scope.Bar = undefined;
bar.get(function (data) {
scope.Bar = data;
});
// Shorthand, ala $resource.get, only supports object types
scope.Baz = baz.get();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment