2 * An Angular module that gives you access to the browsers local storage
3 * @version v0.2.3 - 2015-10-11
4 * @link https://github.com/grevory/angular-local-storage
5 * @author grevory <greg@gregpike.ca>
6 * @license MIT License, http://www.opensource.org/licenses/MIT
8 (function ( window, angular, undefined ) {
9 /*jshint globalstrict:true*/
12 var isDefined = angular.isDefined,
13 isUndefined = angular.isUndefined,
14 isNumber = angular.isNumber,
15 isObject = angular.isObject,
16 isArray = angular.isArray,
17 extend = angular.extend,
18 toJson = angular.toJson;
19 var angularLocalStorage = angular.module('LocalStorageModule', []);
21 angularLocalStorage.provider('localStorageService', function() {
23 // You should set a prefix to avoid overwriting any local storage variables from the rest of your app
24 // e.g. localStorageServiceProvider.setPrefix('yourAppName');
25 // With provider you can use config as this:
26 // myApp.config(function (localStorageServiceProvider) {
27 // localStorageServiceProvider.prefix = 'yourAppName';
31 // You could change web storage type localstorage or sessionStorage
32 this.storageType = 'localStorage';
34 // Cookie options (usually in case of fallback)
35 // expiry = Number of days before cookies expire // 0 = Does not expire
36 // path = The web path the cookie represents
42 // Send signals for each of the following actions?
48 // Setter for the prefix
49 this.setPrefix = function(prefix) {
54 // Setter for the storageType
55 this.setStorageType = function(storageType) {
56 this.storageType = storageType;
60 // Setter for cookie config
61 this.setStorageCookie = function(exp, path) {
62 this.cookie.expiry = exp;
63 this.cookie.path = path;
67 // Setter for cookie domain
68 this.setStorageCookieDomain = function(domain) {
69 this.cookie.domain = domain;
73 // Setter for notification config
74 // itemSet & itemRemove should be booleans
75 this.setNotify = function(itemSet, itemRemove) {
78 removeItem: itemRemove
83 this.$get = ['$rootScope', '$window', '$document', '$parse', function($rootScope, $window, $document, $parse) {
85 var prefix = self.prefix;
86 var cookie = self.cookie;
87 var notify = self.notify;
88 var storageType = self.storageType;
91 // When Angular's $document is not available
94 } else if ($document[0]) {
95 $document = $document[0];
98 // If there is a prefix set in the config lets use that with an appended period for readability
99 if (prefix.substr(-1) !== '.') {
100 prefix = !!prefix ? prefix + '.' : '';
102 var deriveQualifiedKey = function(key) {
105 // Checks the browser to see if local storage is supported
106 var browserSupportsLocalStorage = (function () {
108 var supported = (storageType in $window && $window[storageType] !== null);
110 // When Safari (OS X or iOS) is in private browsing mode, it appears as though localStorage
111 // is available, but trying to call .setItem throws an exception.
113 // "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage
114 // that exceeded the quota."
115 var key = deriveQualifiedKey('__' + Math.round(Math.random() * 1e7));
117 webStorage = $window[storageType];
118 webStorage.setItem(key, '');
119 webStorage.removeItem(key);
124 storageType = 'cookie';
125 $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
130 // Directly adds a value to local storage
131 // If local storage is not available in the browser use cookies
132 // Example use: localStorageService.add('library','angular');
133 var addToLocalStorage = function (key, value) {
134 // Let's convert undefined values to null to get the value consistent
135 if (isUndefined(value)) {
138 value = toJson(value);
141 // If this browser does not support local storage use cookies
142 if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
143 if (!browserSupportsLocalStorage) {
144 $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
147 if (notify.setItem) {
148 $rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: 'cookie'});
150 return addToCookies(key, value);
155 webStorage.setItem(deriveQualifiedKey(key), value);
157 if (notify.setItem) {
158 $rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: self.storageType});
161 $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
162 return addToCookies(key, value);
167 // Directly get a value from local storage
168 // Example use: localStorageService.get('library'); // returns 'angular'
169 var getFromLocalStorage = function (key) {
171 if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
172 if (!browserSupportsLocalStorage) {
173 $rootScope.$broadcast('LocalStorageModule.notification.warning','LOCAL_STORAGE_NOT_SUPPORTED');
176 return getFromCookies(key);
179 var item = webStorage ? webStorage.getItem(deriveQualifiedKey(key)) : null;
180 // angular.toJson will convert null to 'null', so a proper conversion is needed
181 // FIXME not a perfect solution, since a valid 'null' string can't be stored
182 if (!item || item === 'null') {
187 return JSON.parse(item);
193 // Remove an item from local storage
194 // Example use: localStorageService.remove('library'); // removes the key/value pair of library='angular'
195 var removeFromLocalStorage = function () {
197 for (i=0; i<arguments.length; i++) {
199 if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
200 if (!browserSupportsLocalStorage) {
201 $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
204 if (notify.removeItem) {
205 $rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: 'cookie'});
207 removeFromCookies(key);
211 webStorage.removeItem(deriveQualifiedKey(key));
212 if (notify.removeItem) {
213 $rootScope.$broadcast('LocalStorageModule.notification.removeitem', {
215 storageType: self.storageType
219 $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
220 removeFromCookies(key);
226 // Return array of keys for local storage
227 // Example use: var keys = localStorageService.keys()
228 var getKeysForLocalStorage = function () {
230 if (!browserSupportsLocalStorage) {
231 $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
235 var prefixLength = prefix.length;
237 for (var key in webStorage) {
238 // Only return keys that are for this app
239 if (key.substr(0,prefixLength) === prefix) {
241 keys.push(key.substr(prefixLength));
243 $rootScope.$broadcast('LocalStorageModule.notification.error', e.Description);
251 // Remove all data for this app from local storage
252 // Also optionally takes a regular expression string and removes the matching key-value pairs
253 // Example use: localStorageService.clearAll();
254 // Should be used mostly for development purposes
255 var clearAllFromLocalStorage = function (regularExpression) {
257 // Setting both regular expressions independently
258 // Empty strings result in catchall RegExp
259 var prefixRegex = !!prefix ? new RegExp('^' + prefix) : new RegExp();
260 var testRegex = !!regularExpression ? new RegExp(regularExpression) : new RegExp();
262 if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
263 if (!browserSupportsLocalStorage) {
264 $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
266 return clearAllFromCookies();
269 var prefixLength = prefix.length;
271 for (var key in webStorage) {
272 // Only remove items that are for this app and match the regular expression
273 if (prefixRegex.test(key) && testRegex.test(key.substr(prefixLength))) {
275 removeFromLocalStorage(key.substr(prefixLength));
277 $rootScope.$broadcast('LocalStorageModule.notification.error',e.message);
278 return clearAllFromCookies();
285 // Checks the browser to see if cookies are supported
286 var browserSupportsCookies = (function() {
288 return $window.navigator.cookieEnabled ||
289 ("cookie" in $document && ($document.cookie.length > 0 ||
290 ($document.cookie = "test").indexOf.call($document.cookie, "test") > -1));
292 $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
297 // Directly adds a value to cookies
298 // Typically used as a fallback is local storage is not available in the browser
299 // Example use: localStorageService.cookie.add('library','angular');
300 var addToCookies = function (key, value, daysToExpiry) {
302 if (isUndefined(value)) {
304 } else if(isArray(value) || isObject(value)) {
305 value = toJson(value);
308 if (!browserSupportsCookies) {
309 $rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
315 expiryDate = new Date(),
318 if (value === null) {
319 // Mark that the cookie has expired one day ago
320 expiryDate.setTime(expiryDate.getTime() + (-1 * 24 * 60 * 60 * 1000));
321 expiry = "; expires=" + expiryDate.toGMTString();
323 } else if (isNumber(daysToExpiry) && daysToExpiry !== 0) {
324 expiryDate.setTime(expiryDate.getTime() + (daysToExpiry * 24 * 60 * 60 * 1000));
325 expiry = "; expires=" + expiryDate.toGMTString();
326 } else if (cookie.expiry !== 0) {
327 expiryDate.setTime(expiryDate.getTime() + (cookie.expiry * 24 * 60 * 60 * 1000));
328 expiry = "; expires=" + expiryDate.toGMTString();
331 var cookiePath = "; path=" + cookie.path;
333 cookieDomain = "; domain=" + cookie.domain;
335 $document.cookie = deriveQualifiedKey(key) + "=" + encodeURIComponent(value) + expiry + cookiePath + cookieDomain;
338 $rootScope.$broadcast('LocalStorageModule.notification.error',e.message);
344 // Directly get a value from a cookie
345 // Example use: localStorageService.cookie.get('library'); // returns 'angular'
346 var getFromCookies = function (key) {
347 if (!browserSupportsCookies) {
348 $rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
352 var cookies = $document.cookie && $document.cookie.split(';') || [];
353 for(var i=0; i < cookies.length; i++) {
354 var thisCookie = cookies[i];
355 while (thisCookie.charAt(0) === ' ') {
356 thisCookie = thisCookie.substring(1,thisCookie.length);
358 if (thisCookie.indexOf(deriveQualifiedKey(key) + '=') === 0) {
359 var storedValues = decodeURIComponent(thisCookie.substring(prefix.length + key.length + 1, thisCookie.length));
361 return JSON.parse(storedValues);
370 var removeFromCookies = function (key) {
371 addToCookies(key,null);
374 var clearAllFromCookies = function () {
375 var thisCookie = null, thisKey = null;
376 var prefixLength = prefix.length;
377 var cookies = $document.cookie.split(';');
378 for(var i = 0; i < cookies.length; i++) {
379 thisCookie = cookies[i];
381 while (thisCookie.charAt(0) === ' ') {
382 thisCookie = thisCookie.substring(1, thisCookie.length);
385 var key = thisCookie.substring(prefixLength, thisCookie.indexOf('='));
386 removeFromCookies(key);
390 var getStorageType = function() {
394 // Add a listener on scope variable to save its changes to local storage
395 // Return a function which when called cancels binding
396 var bindToScope = function(scope, key, def, lsKey) {
397 lsKey = lsKey || key;
398 var value = getFromLocalStorage(lsKey);
400 if (value === null && isDefined(def)) {
402 } else if (isObject(value) && isObject(def)) {
403 value = extend(def, value);
406 $parse(key).assign(scope, value);
408 return scope.$watch(key, function(newVal) {
409 addToLocalStorage(lsKey, newVal);
410 }, isObject(scope[key]));
413 // Return localStorageService.length
414 // ignore keys that not owned
415 var lengthOfLocalStorage = function() {
417 var storage = $window[storageType];
418 for(var i = 0; i < storage.length; i++) {
419 if(storage.key(i).indexOf(prefix) === 0 ) {
427 isSupported: browserSupportsLocalStorage,
428 getStorageType: getStorageType,
429 set: addToLocalStorage,
430 add: addToLocalStorage, //DEPRECATED
431 get: getFromLocalStorage,
432 keys: getKeysForLocalStorage,
433 remove: removeFromLocalStorage,
434 clearAll: clearAllFromLocalStorage,
436 deriveKey: deriveQualifiedKey,
437 length: lengthOfLocalStorage,
439 isSupported: browserSupportsCookies,
441 add: addToCookies, //DEPRECATED
443 remove: removeFromCookies,
444 clearAll: clearAllFromCookies
449 })( window, window.angular );