- Notifications
You must be signed in to change notification settings - Fork114
A better way to use localStorage and sessionStorage
License
nbubna/store
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
A feature-filled and friendly way to take advantage of localStorage and sessionStorage(JSON, namespacing, extensions, etc).
Download:store2.min.js orstore2.js
NPM:npm install store2
NuGet:Install-Package store2
The main store function can handleset
,get
,transact
,setAll
,getAll
,each
, andclear
actions directly. Respectively, these are called like so:
store(key,data);// sets stringified data under keystore(key);// gets and parses data stored under keystore(key,fn[,alt]);// run transaction function on/with data stored under keystore({key:data,key2:data2});// sets all key/data pairs in the objectstore();// gets all stored key/data pairs as an objectstore((key,data)=>{});// calls function for each key/data in storage, return false to exitstore(false);// clears all items from storage
Parameters in [brackets] are optional. There are also more explicit and versatile functions available:
store.set(key,data[,overwrite]);// === store(key, data);store.setAll(data[,overwrite]);// === store({key: data, key2: data});store.get(key[,alt]);// === store(key);store.getAll([fillObj]);// === store();store.transact(key,fn[,alt]);// === store(key, fn[, alt]);store.clear();// === store(false);store.has(key);// returns true or falsestore.remove(key[,alt]);// removes key and its data, then returns the data or alt, if nonestore.each(fn[,fill]);// === store(fn); optional call arg will be 3rd fn arg (e.g. for gathering values)store.add(key,data[,replacer]);// concats, merges, or adds new value into existing onestore.keys([fillList]);// returns array of keysstore.size();// number of keys, not length of datastore.clearAll();// clears *ALL* areas (but still namespace sensitive)
Passing infalse
for the optional overwrite parameters will causeset
actions to be skippedif the storage already has a value for that key. Allset
action methods return the previous valuefor that key, by default. If overwrite isfalse
and there is a previous value, the unused newvalue will be returned.
Functions passed totransact
will receive the current value for that key as an argument ora passed alternate if there is none. When the passed function is completed, transact will save the returned valueunder the specified key. If the function returnsundefined
, the original value will be saved.This makes it easy for transact functions to change internal properties in a persistent way:
store.transact(key,function(obj){obj.changed='newValue';// this change will be persisted});
Functions passed toeach
will receive the key as first argument and current value as the second; if afill
parameter is specified, it's value will be the third argument for every call (few should everneed afill
parameter). If the function returnsfalse
at any point during the iteration, theloop will exit early and not continue on to the next key/value pair.
store.each(function(key,value){console.log(key,'->',value);if(key==='stopLoop'){returnfalse;// this will cause each to stop calling this function}});
All retrieval functions which take an optionalalt
parameter can also use that parameter to specify a "reviver" function. These receive each key and value (yes, nested ones too) as arguments and allow you to provide an alternate means of parsing that string. This is particularly useful for rich objects likeDate
types. SeeMDN's JSON.parse docs for more information and examples. Alternately, you can set a global reviver to thestore._.revive
property to handle allget
,getAll
,remove
, andtransact
calls.
Likewise, setter functions which take an optionaloverwrite
parameter can also use that parameter to accept a "replacer" function that receives each key and value (yes, nested ones too) as arguments and allow you to provide an alternate means of stringifying the values. This is particularly useful for rich objects likeMap
orSet
. SeeMDN's JSON.stringify docs for more information and examples. Alternately, you can set a global replacer to thestore._.replace
property to handle allset
,setAll
,add
, andtransact
calls.
ForgetAll
andkeys
, there is the option to pass in the object or list, respectively,that you want the results to be added to. This is instead of an empty list.There are only a few special cases where you are likely to need or want this,in general, most users should ignore these optional parameters.These both use the second, optional argumenteach
function,which is also a niche feature. Thevalue
argument is passed asthe second arg to the callback function (in place of the data associated with the current key)and is returned at the end. Again, most users should not need this feature.All of these use the browser's localStorage (aka "local"). Using sessionStorage merely requirescalling the same functions onstore.session
:
store.session("addMeTo","sessionStorage");store.local({lots:'of',data:'altogether'});// store.local === store :)
There is also a store API automatically available for keeping non-persistent information,meant only to last until page reload.
store.page("until","reload");
All the specificget
,set
, etc. functions are available onstore.session
,store.local
, andstore.page
, as well as any other storage facility registered viastore.area(name, customStorageObject)
by an extension, where customStorageObject must implement theStorage interface. This is howstore.old.js extends store.js to support older versions of IE and Firefox.
If you want to put stored data from different pages or areas f your site into separate namespaces,thestore.namespace(ns)
function is your friend:
varcart=store.namespace('cart');cart('total',23.25);// stores in localStorage as 'cart.total'console.log(store('cart.total')==cart('total'));// logs trueconsole.log(store.cart.getAll());// logs {total: 23.25}cart.session('group','toys');// stores in sessionStorage as 'cart.group'
The namespace provides the same exact API asstore
but silently adds/removes the namespace prefix as needed.It also makes the namespaced API accessible directly viastore[namespace]
(e.g.store.cart
) as long as itdoes not conflict with an existing part of the store API.
The 'namespace' function is one of three "extra" functions that are also part of the "store API":
store.namespace(prefix);// returns a new store API that prefixes all key-based functionsstore.isFake([force]);// test or set whether localStorage/sessionStorage or an in-memory, 'fake' storage is used
store.namespace
can also take extra params to only create the namespace in the called-on storage area, andto pass in an alternate namespace delimiter for advanced use-cases (e.g.store.page.namespace("subpage", true, ":")
).
If localStorage or sessionStorage are unavailable, they will be faked to prevent errors,but data stored will NOT persist beyond the life of the current document/page. Use thestore.old.js extension to add persistent backing for the store API in ancient browsers.
isFake(true|false)
is particularly useful to force use of a temporary, fake storage in testing situations,to prevent cluttering actual storage.
These mostly could use further documentation and abuse...er...testing.Contributions are welcome!In particular, any ES6 user interested in making theseimportable in ES6 would be appreciated.
- store.old.js - Add working localStorage and sessionStorage polyfills for ancient browsers
- store.overflow.js - Fall back to fake storage on quota errors
- store.cache.js - To make data expire, pass a number of seconds as the overwrite (third) param on
set()
calls - store.on.js - Superior storage event handling (per key, per namespace, etc in IE9+)
- store.array.js - Easy, powerful array functions for any and all data (e.g.
store.push(key, v1, v2)
). - store.dom.js - Declarative, persistent DOM element content via store.
- store.cookie.js - Support for a cookie as a storage area:
store.cookie('num',1)
to make sharing with backend easier.
- store.quota.js - Register callbacks to handle (and even cancel) quota errors
- store.measure.js - Experimental extension for measuring space used and available (needs work)
- store.onlyreal.js - When only fake storage is available, silently fail instead of faking it.
- store.dot.js - Creates accessors for keys (e.g.
store.foo == store.get('foo')
) - store.deep.js - Allow retrieval of properties from within stored objects (e.g.
store.get('key.property')
) - store.async.js - Adds
store.async
duplicate to each store and namespace that performs functions asynchronously and returns a Promise that resolves when complete. - store.cookies.js - Support managing all cookies as a storage area with the store API (e.g.
store.cookies.get('user')
)
To write your own extension, you can use or carefully override internal functions exposed asstore._
.In particular, thestore._.fn(fnName, fn)
method is available to automatically add your new functionto every instance of thestore
interface (e.g.store
,store.session
and all existing and future namespaces). Take care using this, as it will override existing methods.Here is a simple example:
(function(_){_.fn('falsy',function(key){return!this.get(key);});_.fn('truthy',function(key){return!this.falsy(key);});})(store._);
This extension would be used like so:
store('foo',1);store.falsy('foo');// returns falsestore.session('bar','one');store.session.truthy('bar');// return true;constwidgetStore=store.namespace('widget');widgetStore.falsy('state');// returns true
- 2010-02-10 v0.1 (extraction from esha.js)
- 2010-05-25 v1.0 (internal release)
- 2013-04-09v2.0.3 (public) - First GitHub release
- 2013-04-20v2.1.0 (public) - Drops flawed/confusing/unused key(i) method, fixes extension problems.
- 2013-04-30v2.1.1 (public) - Browserify (and friends) support (module.exports = store)
- 2013-05-30v2.1.2 (public) - Component support (old component.json is now bower.json)
- 2014-03-10v2.1.6 (public) - AMD support and Component improvements
- 2015-02-02v2.2.0 (public) - Change store.cache.js to use seconds, not minutes.
- 2015-05-05v2.2.1 (public) - node.js compatibility
- 2015-05-08v2.2.2 (public) - Always expose global to allow extensions to always work.
- 2015-05-22v2.3.0 (public) - Use fake storage for Safari private mode (instead of letting quota exceptions go)
- 2015-10-27v2.3.2 (public) - Add source map
- 2017-01-04v2.4.0 (public) - Add store.transact(key, fn[, alt])
- 2017-01-09v2.5.0 (public) - Update for issue #34; new extensions (array, dot, and deep); only expose global in non-AMD/CommonJS environments (PR #35)
- 2017-08-09v2.5.2 (public) - Fix
clear()
in fake storage (thx to Martin Kluska) - 2018-01-18v2.5.11 (public) - Add
index.d.ts
in root to provide TypeScript support - 2018-01-23v2.6.0 (public) - Support
each(fn,value)
,getAll(fillObj)
, andkeys(fillList)
to support some advanced/corner cases - 2018-11-15v2.7.1 (public) - Add
add(key, data)
for common case of saving a combination of existing and new data. Fix issue #60. - 2019-07-23v2.8.0 (public) - Add
store(fn)
shortcut forstore.each
, copy properties when inheriting, and makestore.each(fn, fill)
always send fill as 3rd arg instead of replacing values. - 2019-08-21v2.9.0 (public) - Add store.remove(key, alt) to match behavior of store.get(key, alt) (Issue #68)
- 2019-09-27v2.10.0 (public) - Add
store.page
to provide page scope storage to complement local and session scope storage. (Issue #69) - 2020-03-23 [v2.11.0][] (public) - Add
store.get(key, reviveFn)
and ```store._.revive`` to support parsing for rich types (e.g. Date) - 2020-04-14v2.11.1 (public) - Fix falsey alt value support in
store.get(key, alt)
- 2020-05-11v2.11.2 (public) - Fix missing TS declaration of new page scope storage.
- 2020-08-12v2.12.0 (public) - PRs for better Storage typing, better testKey, and dev dependency updates.
- 2021-12-16v2.13.1 (public) - Add
store.set(key, value, replacerFn)
,store._replace
, andisFake([force])
to support stringifying rich types and easier testing. And cookie-based extensions for using store backed by a single 'store' cookie or store API for all cookies. - 2022-03-14v2.13.2 (public) - Restore missing TS declaration of store.area(id[, area])
- 2022-05-11v2.14.0 (public) - Allow namespace delimiter to be changed via store._.nsdelim
- 2022-07-14v2.14.1 (public) - Fix change to
set
that broke store.cache.js, and allow namespace delimiter to be passed tonamespace(name, thisAreaOnly, delim)
for a single namespace, to avoid conflicts. - 2022-07-18v2.14.2 (public) - Fix typo in
index.d.ts
typings. - 2024-02-14v2.14.3 (public) - Cut license options to just MIT, also removed Bower and Component support since those are long dead.
- 2024-12-26v2.14.4 (public) - Remove use of eval from store.deep.js
About
A better way to use localStorage and sessionStorage