2 * An Angular module that gives you access to the browsers local storage
3 * @version v0.2.6 - 2016-03-16
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) {
9 var isDefined = angular.isDefined,
10 isUndefined = angular.isUndefined,
11 isNumber = angular.isNumber,
12 isObject = angular.isObject,
13 isArray = angular.isArray,
14 extend = angular.extend,
15 toJson = angular.toJson;
18 .module('LocalStorageModule', [])
19 .provider('localStorageService', function() {
20 // You should set a prefix to avoid overwriting any local storage variables from the rest of your app
21 // e.g. localStorageServiceProvider.setPrefix('yourAppName');
22 // With provider you can use config as this:
23 // myApp.config(function (localStorageServiceProvider) {
24 // localStorageServiceProvider.prefix = 'yourAppName';
28 // You could change web storage type localstorage or sessionStorage
29 this.storageType = 'localStorage';
31 // Cookie options (usually in case of fallback)
32 // expiry = Number of days before cookies expire // 0 = Does not expire
33 // path = The web path the cookie represents
39 // Send signals for each of the following actions?
45 // Setter for the prefix
46 this.setPrefix = function(prefix) {
51 // Setter for the storageType
52 this.setStorageType = function(storageType) {
53 this.storageType = storageType;
57 // Setter for cookie config
58 this.setStorageCookie = function(exp, path) {
59 this.cookie.expiry = exp;
60 this.cookie.path = path;
64 // Setter for cookie domain
65 this.setStorageCookieDomain = function(domain) {
66 this.cookie.domain = domain;
70 // Setter for notification config
71 // itemSet & itemRemove should be booleans
72 this.setNotify = function(itemSet, itemRemove) {
75 removeItem: itemRemove
80 this.$get = ['$rootScope', '$window', '$document', '$parse', function($rootScope, $window, $document, $parse) {
82 var prefix = self.prefix;
83 var cookie = self.cookie;
84 var notify = self.notify;
85 var storageType = self.storageType;
88 // When Angular's $document is not available
91 } else if ($document[0]) {
92 $document = $document[0];
95 // If there is a prefix set in the config lets use that with an appended period for readability
96 if (prefix.substr(-1) !== '.') {
97 prefix = !!prefix ? prefix + '.' : '';
99 var deriveQualifiedKey = function(key) {
102 // Checks the browser to see if local storage is supported
103 var browserSupportsLocalStorage = (function () {
105 var supported = (storageType in $window && $window[storageType] !== null);
107 // When Safari (OS X or iOS) is in private browsing mode, it appears as though localStorage
108 // is available, but trying to call .setItem throws an exception.
110 // "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage
111 // that exceeded the quota."
112 var key = deriveQualifiedKey('__' + Math.round(Math.random() * 1e7));
114 webStorage = $window[storageType];
115 webStorage.setItem(key, '');
116 webStorage.removeItem(key);
121 storageType = 'cookie';
122 $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
127 // Directly adds a value to local storage
128 // If local storage is not available in the browser use cookies
129 // Example use: localStorageService.add('library','angular');
130 var addToLocalStorage = function (key, value) {
131 // Let's convert undefined values to null to get the value consistent
132 if (isUndefined(value)) {
135 value = toJson(value);
138 // If this browser does not support local storage use cookies
139 if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
140 if (!browserSupportsLocalStorage) {
141 $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
144 if (notify.setItem) {
145 $rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: 'cookie'});
147 return addToCookies(key, value);
152 webStorage.setItem(deriveQualifiedKey(key), value);
154 if (notify.setItem) {
155 $rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: self.storageType});
158 $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
159 return addToCookies(key, value);
164 // Directly get a value from local storage
165 // Example use: localStorageService.get('library'); // returns 'angular'
166 var getFromLocalStorage = function (key) {
168 if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
169 if (!browserSupportsLocalStorage) {
170 $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
173 return getFromCookies(key);
176 var item = webStorage ? webStorage.getItem(deriveQualifiedKey(key)) : null;
177 // angular.toJson will convert null to 'null', so a proper conversion is needed
178 // FIXME not a perfect solution, since a valid 'null' string can't be stored
179 if (!item || item === 'null') {
184 return JSON.parse(item);
190 // Remove an item from local storage
191 // Example use: localStorageService.remove('library'); // removes the key/value pair of library='angular'
192 var removeFromLocalStorage = function () {
194 for (i=0; i<arguments.length; i++) {
196 if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
197 if (!browserSupportsLocalStorage) {
198 $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
201 if (notify.removeItem) {
202 $rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: 'cookie'});
204 removeFromCookies(key);
208 webStorage.removeItem(deriveQualifiedKey(key));
209 if (notify.removeItem) {
210 $rootScope.$broadcast('LocalStorageModule.notification.removeitem', {
212 storageType: self.storageType
216 $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
217 removeFromCookies(key);
223 // Return array of keys for local storage
224 // Example use: var keys = localStorageService.keys()
225 var getKeysForLocalStorage = function () {
227 if (!browserSupportsLocalStorage) {
228 $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
232 var prefixLength = prefix.length;
234 for (var key in webStorage) {
235 // Only return keys that are for this app
236 if (key.substr(0, prefixLength) === prefix) {
238 keys.push(key.substr(prefixLength));
240 $rootScope.$broadcast('LocalStorageModule.notification.error', e.Description);
248 // Remove all data for this app from local storage
249 // Also optionally takes a regular expression string and removes the matching key-value pairs
250 // Example use: localStorageService.clearAll();
251 // Should be used mostly for development purposes
252 var clearAllFromLocalStorage = function (regularExpression) {
254 // Setting both regular expressions independently
255 // Empty strings result in catchall RegExp
256 var prefixRegex = !!prefix ? new RegExp('^' + prefix) : new RegExp();
257 var testRegex = !!regularExpression ? new RegExp(regularExpression) : new RegExp();
259 if (!browserSupportsLocalStorage || self.storageType === 'cookie') {
260 if (!browserSupportsLocalStorage) {
261 $rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
263 return clearAllFromCookies();
266 var prefixLength = prefix.length;
268 for (var key in webStorage) {
269 // Only remove items that are for this app and match the regular expression
270 if (prefixRegex.test(key) && testRegex.test(key.substr(prefixLength))) {
272 removeFromLocalStorage(key.substr(prefixLength));
274 $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
275 return clearAllFromCookies();
282 // Checks the browser to see if cookies are supported
283 var browserSupportsCookies = (function() {
285 return $window.navigator.cookieEnabled ||
286 ("cookie" in $document && ($document.cookie.length > 0 ||
287 ($document.cookie = "test").indexOf.call($document.cookie, "test") > -1));
289 $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
294 // Directly adds a value to cookies
295 // Typically used as a fallback is local storage is not available in the browser
296 // Example use: localStorageService.cookie.add('library','angular');
297 var addToCookies = function (key, value, daysToExpiry) {
299 if (isUndefined(value)) {
301 } else if(isArray(value) || isObject(value)) {
302 value = toJson(value);
305 if (!browserSupportsCookies) {
306 $rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
312 expiryDate = new Date(),
315 if (value === null) {
316 // Mark that the cookie has expired one day ago
317 expiryDate.setTime(expiryDate.getTime() + (-1 * 24 * 60 * 60 * 1000));
318 expiry = "; expires=" + expiryDate.toGMTString();
320 } else if (isNumber(daysToExpiry) && daysToExpiry !== 0) {
321 expiryDate.setTime(expiryDate.getTime() + (daysToExpiry * 24 * 60 * 60 * 1000));
322 expiry = "; expires=" + expiryDate.toGMTString();
323 } else if (cookie.expiry !== 0) {
324 expiryDate.setTime(expiryDate.getTime() + (cookie.expiry * 24 * 60 * 60 * 1000));
325 expiry = "; expires=" + expiryDate.toGMTString();
328 var cookiePath = "; path=" + cookie.path;
330 cookieDomain = "; domain=" + cookie.domain;
332 $document.cookie = deriveQualifiedKey(key) + "=" + encodeURIComponent(value) + expiry + cookiePath + cookieDomain;
335 $rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
341 // Directly get a value from a cookie
342 // Example use: localStorageService.cookie.get('library'); // returns 'angular'
343 var getFromCookies = function (key) {
344 if (!browserSupportsCookies) {
345 $rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
349 var cookies = $document.cookie && $document.cookie.split(';') || [];
350 for(var i=0; i < cookies.length; i++) {
351 var thisCookie = cookies[i];
352 while (thisCookie.charAt(0) === ' ') {
353 thisCookie = thisCookie.substring(1,thisCookie.length);
355 if (thisCookie.indexOf(deriveQualifiedKey(key) + '=') === 0) {
356 var storedValues = decodeURIComponent(thisCookie.substring(prefix.length + key.length + 1, thisCookie.length));
358 return JSON.parse(storedValues);
367 var removeFromCookies = function (key) {
368 addToCookies(key,null);
371 var clearAllFromCookies = function () {
372 var thisCookie = null, thisKey = null;
373 var prefixLength = prefix.length;
374 var cookies = $document.cookie.split(';');
375 for(var i = 0; i < cookies.length; i++) {
376 thisCookie = cookies[i];
378 while (thisCookie.charAt(0) === ' ') {
379 thisCookie = thisCookie.substring(1, thisCookie.length);
382 var key = thisCookie.substring(prefixLength, thisCookie.indexOf('='));
383 removeFromCookies(key);
387 var getStorageType = function() {
391 // Add a listener on scope variable to save its changes to local storage
392 // Return a function which when called cancels binding
393 var bindToScope = function(scope, key, def, lsKey) {
394 lsKey = lsKey || key;
395 var value = getFromLocalStorage(lsKey);
397 if (value === null && isDefined(def)) {
399 } else if (isObject(value) && isObject(def)) {
400 value = extend(value, def);
403 $parse(key).assign(scope, value);
405 return scope.$watch(key, function(newVal) {
406 addToLocalStorage(lsKey, newVal);
407 }, isObject(scope[key]));
410 // Return localStorageService.length
411 // ignore keys that not owned
412 var lengthOfLocalStorage = function() {
414 var storage = $window[storageType];
415 for(var i = 0; i < storage.length; i++) {
416 if(storage.key(i).indexOf(prefix) === 0 ) {
424 isSupported: browserSupportsLocalStorage,
425 getStorageType: getStorageType,
426 set: addToLocalStorage,
427 add: addToLocalStorage, //DEPRECATED
428 get: getFromLocalStorage,
429 keys: getKeysForLocalStorage,
430 remove: removeFromLocalStorage,
431 clearAll: clearAllFromLocalStorage,
433 deriveKey: deriveQualifiedKey,
434 length: lengthOfLocalStorage,
436 isSupported: browserSupportsCookies,
438 add: addToCookies, //DEPRECATED
440 remove: removeFromCookies,
441 clearAll: clearAllFromCookies
446 })(window, window.angular);