angular-local-storage
An AngularJS provider that gives 1.x apps a unified API over localStorage, sessionStorage, and cookies, with automatic fallback when web storage isn't available.
Repository Health
Technical Analysis
angular-local-storage is a small AngularJS (1.x) module that wraps the browser’s Web Storage API behind a single localStorageService provider. Instead of calling window.localStorage directly and handling QuotaExceededError or private-browsing edge cases yourself, you inject the service and call .set(), .get(), .remove(), .keys(), and .clearAll() — the module silently falls back to cookies when localStorage is unsupported or disabled (notably Safari private mode, where localStorage exists but throws on write).
The provider is configured once at bootstrap (localStorageServiceProvider.setPrefix(...), .setStorageType(...), .setStorageCookie(...)) and exposes runtime methods afterward, following the standard Angular provider/service split. A bind() helper wires a $scope property directly to a storage key so changes persist automatically, and $rootScope broadcasts (LocalStorageModule.notification.setitem, .removeitem, .error, .warning) let the rest of the app react to storage events without polling.
It shipped its first tagged release in 2014 and its last in 2017, reflecting the AngularJS (not Angular 2+) ecosystem it targets; 86 contributors and 2.8k GitHub stars point to broad historical adoption, largely from apps built during Angular 1.x’s peak years that needed a dependable, cookie-aware storage abstraction without adding a heavier dependency.
What You Get
- A
localStorageServicewithset/get/remove/keys/clearAll/lengthmethods that mirror the native Web Storage API but with JSON serialization built in - Automatic cookie fallback when localStorage is unavailable or throws (e.g. Safari private browsing), configurable via
setDefaultToCookie - A
bind(scope, property, [value], [key])helper that keeps a$scopeproperty and a storage key in sync automatically - Per-key namespacing via
setPrefixso multiple apps or modules sharing a domain don’t collide in storage - A nested
cookiesub-API (localStorageService.cookie.set/get/remove/clearAll) for direct cookie access with expiry, path, and secure-flag options $rootScopeevent broadcasts on set/remove/error so other parts of an app can observe storage changes reactively
Common Use Cases
- Persisting user preferences (theme, layout, language) across page reloads in a legacy AngularJS single-page app
- Caching form input or wizard state client-side so users don’t lose progress on accidental navigation
- Storing an auth token or session flag with automatic fallback to cookies for browsers/modes that block localStorage
- Two-way binding a
$scopevalue directly to persisted storage viabind()to avoid writing manual watch/save boilerplate - Namespacing storage keys per sub-app when several AngularJS modules share the same origin
Under The Hood
Architecture
The entire module lives in one file, src/angular-local-storage.js, registered as LocalStorageModule with a single localStorageServiceProvider. Angular’s provider pattern separates configuration time (this.setPrefix, this.setStorageType, this.setStorageCookie, called inside .config() blocks) from runtime (this.$get returns the actual localStorageService injected into controllers/services). Internally, every public method (addToLocalStorage, getFromLocalStorage, removeFromLocalStorage, getKeysForLocalStorage) follows the same shape: snapshot the current storage type, optionally override it per-call, run the operation, then restore the previous type in a finally block — a deliberate technique for supporting the type override parameter without leaking state across calls. A checkSupport() probe run once at startup writes and immediately removes a throwaway key to detect Safari private-mode’s silent QuotaExceededError, flipping storageType to 'cookie' if the probe fails. There’s no build step separating source from distributable; dist/angular-local-storage.js is a checked-in, manually-regenerated copy of src/.
Tech Stack
Pure AngularJS 1.x (^1.x per bower.json) with zero runtime dependencies beyond Angular itself — no bundler-era tooling. Development tooling is entirely Grunt-based: grunt-contrib-jshint for linting, grunt-contrib-concat/grunt-contrib-uglify for building dist/, and grunt-karma with karma-jasmine and karma-phantomjs-launcher for running the test suite headlessly. Package distribution is dual: npm (index.js re-exports the dist build for CommonJS/Browserify consumers) and Bower (bower.json points at the same dist file for script-tag consumers), reflecting the pre-webpack front-end packaging conventions of its era. CI ran on Travis with Node 0.10.
Code Quality
The test suite in test/spec/localStorageSpec.js (900+ lines) is thorough for the module’s scope, using Jasmine with a hand-rolled localStorageMock and spyOn assertions to verify that public methods call through to the correct native localStorage/sessionStorage/cookie APIs, including private-mode fallback paths. Error handling is deliberately defensive — nearly every storage operation is wrapped in try/catch with broadcast-based error reporting rather than thrown exceptions, appropriate for a library whose entire premise is tolerating inconsistent browser storage support. Naming is consistent camelCase throughout, and a .jshintrc enforces eqeqeq, curly, camelcase, and single-quote style, though there is no TypeScript or modern type checking. The project has been dormant since 2017 with 64 open issues, consistent with unmaintained-but-stable legacy AngularJS tooling.
What Makes It Unique
The library’s distinguishing choice is treating cookie fallback as a first-class, transparent behavior rather than an opt-in escape hatch: callers use the same .set()/.get() API regardless of whether the browser ultimately stores the value in localStorage or a cookie, with the switch happening automatically based on a real write-probe rather than a typeof feature check. Combined with the bind() scope-sync helper, it offered AngularJS 1.x developers persistence with noticeably less boilerplate than wiring $watch and raw localStorage calls by hand — a pattern later superseded by framework-native solutions in Angular 2+ and React/Vue ecosystems.