persisto
v2.0.2
Published
Persist JavaScript objects to localStorage and remote servers.
Downloads
111
Maintainers
Readme
persisto
Persistent JavaScript objects and web forms using Web Storage.
Features
- Persist JavaScript objects (
{...}
) tolocalStorage
/sessionStorage
. Use theget()
/set()
API for direct (even nested) access, avoiding the need to convert from/to JSON. - Cache access to
localStorage
/sessionStorage
(deferred writing appears to be 10-15 times faster). - Make JavaScript objects editable in HTML forms. A simple naming convention maps data properties to form elements. Listen for input change events and automatically store data.
- Optionally synchronize the data with a remote endpoint.
Overview:
Requirements:
- jQuery not required since v2.0
- Recent major browser (Internet Explorer is not supported!)
Requirements for version 1.x:
- jQuery
- IE 8+ or any recent major browser
Usage
Download the latest persisto.js or include directly from CDN: or UNPKG:
<script src="//cdn.jsdelivr.net/npm/persisto@latest/dist/persisto.umd.min.js"></script>
then instantiate a PersistentObject
:
let store = new mar10.PersistentObject("mySettings", {
defaults: {
theme: "default",
},
});
store
now contains the data that was stored in localStorage.mySettings
if
present. Otherwise, store
is initialized to the default values that we
passed with the .defaults
option.
We can access data using set
, get
, remove
, reset
:
store.get("theme"); // -> 'default'
store.set("owner", { name: "joe", age: 42 });
store.set("owner.role", "manager");
store.get("owner.age"); // -> 42
store.remove("owner.age");
// -> store now holds {theme: "default", owner: {name: "joe", role: "manager"}}
Every modifying operation triggers a deferred commit, so that shortly afterwards
the data is serialized to JSON and written to localStorage.mySettings
.
More:
- Try the online example.
- Run the unit tests.
Synchronize Data with HTML Forms
Form input elements can be synchronized with a PersistentObject
by using two
API calls.
Example:
// Maintain client's preferences and define some defaults:
let settingsStore = new mar10.PersistentObject("mySettings", {
defaults: {
nickname: "anonymous",
theme: "default",
},
});
store.ready.then((value) => {
console.log("PersistentStore is initialized.");
// Allow users to edit and save settings:
document.querySelector("#form1").addEventListener("submit", function (e) {
store.readFromForm("#form1");
e.preventDefault();
});
// Initialize form elements with current data
store.writeToForm("#form1");
});
//document.addEventListener("DOMContentLoaded", function (event) {});
Supported elements are <input>
(type text, checkbox, or radio), <textarea>
,
and <select>
(single and multivalue).
By convention, the html form must use element names that match the data properties.
<form id="settingsForm" action="">
<label>Nickname:<input name="nickname" type="text" value="" /></label><br />
<label
>Theme:
<fieldset>
<label>
<input name="theme" type="radio" value="default" /> Standard </label
><br />
<label> <input name="theme" type="radio" value="light" /> Light </label
><br />
<label> <input name="theme" type="radio" value="dark" /> Dark </label>
</fieldset>
</label>
<button type="Submit">Submit</button>
</form>
Note also that only fields are synchronized, that already existed in the storage
data. Use the addNew
option if all form fields should be evaluated and create
new properties in the store object:
settingsStore.readFromForm(this, {
addNew: true,
});
Pros and Cons
Any
PersistentObject
instance is stored as one monolythic JSON string. Persisto deferres and collates these updates, but modifying a single property of a large data object still comes with some overhead. Splitting data into severalPersistentObject
s may remedy the problem. But if your data model is more like a table with hundredth's of rows, a responsive database backend may be a better choice.Asynchronous operations bear the risk of potential conflicts. There is currently no builtin support for resolving those.
HOWTOs
Storing Arrays
Arrays are only a special form of plain JavaScript objects, so we can store and access them as top level type like this:
let store = new mar10.PersistentObject("mySettings", {
defaults: ["a", "b", "c"],
});
store.get("[0]"); // 'a'
store.set("[1]", "b2");
However if we use child properties, it is even easier:
let store = new mar10.PersistentObject("mySettings", {
defaults: {
values: ["a", "b", "c"]
}
});
store.get("values")[0]; // 'a'
store.get("values[0]"); // 'a'
S.each(store.get("values"), function(idx, obj) { ... });
store.set("values[1]", "b2");
Performance and Direct Access
In general, performance costs of set()
and get()
calls should be
neglectable, compared to the resulting synchronization times, but in some cases
direct access of the internal data object may be preferred.
In this case modifications must be signalled by a call to setDirty()
.
store._data.owner = { name: "joe", age: 42 };
store._data.owner.role = "manager";
delete store._data.owner.age;
store.setDirty(); // schedule a commit
Asynchronous Operation
By default, changed values will be commited to webStorage after a small delay
(see .commitDelay
option). This allows to collate sequences of multiple changes
into one single write command.
However there are situations, where this is not desirable:
store.set("foo", "bar");
// Page reload would prevent the delayed commit from happen, so we force
// synchronization:
store.commit();
location.reload();
An alternative would be to disable delay completely by setting commitDelay: 0
.
Synchronize with Remote Endpoints
Optionally, we may specify an endpoint URL that is used to synchronize the data with a web server using HTTP REST requests (GET and PUT):
// Wait fpr page beeing loaded...
document.addEventListener("DOMContentLoaded", function (event) {
let store = new mar10.PersistentObject("mySettings", {
remote: "persist/settings",
});
store.ready
.then(function (value) {
console.log("PersistentStore is initialized and has pulled data.");
})
.catch(function (reason) {
console.error("Error loading persistent objects", arguments);
});
});
API Reference
Options and Events
The following options are available:
http://mar10.github.io/persisto/interfaces/persisto_options.persistooptions.html
Methods
Following a list of available methods:
http://mar10.github.io/persisto/classes/persisto.persistentobject.html