docs.sheetjs.com/docz/docs/03-demos/27-local/03-storageapi.md

242 lines
7.0 KiB
Markdown
Raw Normal View History

2023-02-24 07:46:48 +00:00
---
title: Local Storage API
2023-09-18 06:44:33 +00:00
pagination_prev: demos/data/index
pagination_next: demos/cloud/index
2023-02-24 07:46:48 +00:00
sidebar_custom_props:
2023-09-18 06:44:33 +00:00
summary: Reading and writing data in an in-browser Key-Value store
2023-02-24 07:46:48 +00:00
---
The Storage API, encompassing `localStorage` and `sessionStorage`, describes
simple key-value stores that only support string values and keys.
2023-02-26 11:38:03 +00:00
This demo covers two common use patterns:
- "Row Objects" shows a simple convention for loading and storing row objects
- "Simple Strings" discusses how to persist and recover a raw Storage
2023-11-30 07:10:37 +00:00
:::note Tested Deployments
2023-09-18 06:44:33 +00:00
Each browser demo was tested in the following environments:
| Browser | Date |
|:------------|:-----------|
2024-03-26 07:33:37 +00:00
| Chrome 122 | 2024-03-25 |
2024-03-14 08:25:08 +00:00
| Safari 17.3 | 2024-03-12 |
2023-09-18 06:44:33 +00:00
:::
2023-02-26 11:38:03 +00:00
## Row Objects
Consider the following array of objects of data:
2023-02-24 07:46:48 +00:00
```js
2023-02-26 11:38:03 +00:00
[
{ Name: "Barack Obama", Index: 44 },
{ Name: "Donald Trump", Index: 45 },
{ Name: "Joseph Biden", Index: 46 }
]
2023-02-24 07:46:48 +00:00
```
2023-02-26 11:38:03 +00:00
Storage API expects values to be strings. The simplest approach is to stringify
row objects using `JSON.stringify` and store using the row index as a key:
| Key | Value |
|:---:|:-------------------------------------|
| 0 | `{"Name":"Barack Obama","Index":44}` |
| 1 | `{"Name":"Donald Trump","Index":45}` |
| 2 | `{"Name":"Joseph Biden","Index":46}` |
#### Importing Data
Starting from a worksheet, `XLSX.utils.sheet_to_json` generates an array of row
objects. `localStorage.setItem` will store data in Local Storage:
2023-02-24 07:46:48 +00:00
```js
2023-02-26 11:38:03 +00:00
function sheet_to_localStorage(worksheet) {
const aoo = XLSX.utils.sheet_to_json(worksheet);
for(let i = 0; i < aoo.length; ++i) {
localStorage.setItem(i, JSON.stringify(aoo[i]));
}
}
2023-02-24 07:46:48 +00:00
```
2023-02-26 11:38:03 +00:00
#### Exporting Data
`localStorage.length` returns the total number of entries. A simple `for` loop
can cover the keys (integers from `0` to `localStorage.length - 1` inclusive)
`localStorage.getItem` will load the stringified data from the Local Storage. A
new array of objects can be constructed by using `JSON.parse` and pushing to an
array. `XLSX.utils.json_to_sheet` can create a new worksheet from that array:
```js
function localStorage_to_sheet() {
const aoo = [];
for(let i = 0; i < localStorage.length; ++i) {
aoo.push(JSON.parse(localStorage.getItem(i)));
}
return XLSX.utils.json_to_sheet(aoo);
}
```
### Live Demo
2024-04-26 04:16:13 +00:00
This demo will fetch https://docs.sheetjs.com/pres.numbers, fill `localStorage`
2023-02-26 11:38:03 +00:00
with rows, then generate a worksheet from the rows and write to a new file.
After saving the exported file, the Local Storage can be inspected in the
"Local Storage" section of the "Application" Tab of Developer Tools:
![Local Storage view in Developer Tools](pathname:///storageapi/lstorage.png)
2023-02-24 07:46:48 +00:00
2023-09-18 06:44:33 +00:00
:::caution pass
2023-02-24 07:46:48 +00:00
This example is for illustration purposes. If array of objects is available, it
is strongly recommended to convert that array to a worksheet directly.
:::
<details>
<summary><b>Live Demo</b> (click to show)</summary>
2023-09-18 06:44:33 +00:00
2023-02-24 07:46:48 +00:00
```jsx live
function SheetJStorage() {
2024-04-26 04:16:13 +00:00
const [url, setUrl] = React.useState("https://docs.sheetjs.com/pres.numbers");
2023-07-21 09:17:32 +00:00
const set_url = (evt) => setUrl(evt.target.value);
2023-02-24 07:46:48 +00:00
const [out, setOut] = React.useState("");
const xport = React.useCallback(async() => {
// get first worksheet data as array of objects
2023-02-26 11:38:03 +00:00
const wb = XLSX.read(await (await fetch(url)).arrayBuffer());
const aoo = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
2023-02-24 07:46:48 +00:00
// reset and populate localStorage
localStorage.clear();
for(var i = 0; i < aoo.length; ++i) localStorage.setItem(i, JSON.stringify(aoo[i]));
// create new array of objects from localStorage
const new_aoo = [];
for(var i = 0; i < localStorage.length; ++i) {
const row = JSON.parse(localStorage.getItem(i));
new_aoo.push(row);
}
setOut(`Number of rows in LocalStorage: ${localStorage.length}`);
// create and export workbook
const new_ws = XLSX.utils.json_to_sheet(new_aoo);
const new_wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(new_wb, new_ws, "Sheet1");
XLSX.writeFile(new_wb, "SheetJStorage.xlsx");
});
2023-02-26 11:38:03 +00:00
return ( <>
2023-02-28 11:40:44 +00:00
{out && ( <><a href={url}>{url}</a><pre>{out}</pre></> )}
2023-02-24 07:46:48 +00:00
<b>URL: </b><input type="text" value={url} onChange={set_url} size="50"/>
<br/><button onClick={xport}><b>Fetch!</b></button>
</> );
}
```
2023-02-26 11:38:03 +00:00
2023-09-18 06:44:33 +00:00
</details>
2023-02-26 11:38:03 +00:00
## Simple Strings
The ["Row Objects" approach](#row-objects) is strongly recommended when trying
to store or recover arrays of row objects.
When the goal is to save an existing Storage, the general representation is an
array of pairs. Consider the following data in Local Storage:
| Key | Value |
|:---:|:----------|
| "b" | "Logical" |
| "n" | "Numeric" |
2023-04-09 21:13:24 +00:00
| "s" | "Textual" |
2023-02-26 11:38:03 +00:00
The natural representation is an array of arrays:
```js
[
[ "b", "Logical" ],
[ "n", "Numeric" ],
[ "s", "Textual" ]
]
```
#### Exporting Storage
2023-09-18 06:44:33 +00:00
:::note pass
2023-04-09 21:13:24 +00:00
Web Storage iteration order is not defined. By using indices as keys, the row
objects approach has an ordering. That does not apply to the general case.
:::
2023-02-26 11:38:03 +00:00
In modern browsers, `Object.entries` will generate an array of key/value pairs.
`XLSX.utils.aoa_to_sheet` will interpret that array as a worksheet with 2 cols:
```js
function localStorage_to_ws() {
const aoa = Object.entries(localStorage);
return XLSX.utils.aoa_to_sheet(aoa);
}
```
#### Importing Storage
In the other direction, the worksheet is assumed to store keys in column A and
values in column B. `XLSX.utils.sheet_to_json` with the `header: 1` option
will generate key/value pairs that can be assigned to a storage:
```js
function ws_to_localStorage(ws) {
const aoa = XLSX.utils.sheet_to_json(ws, { header: 1 });
aoa.forEach(([key, val]) => localStorage.setItem(key, val));
}
```
2023-04-09 21:13:24 +00:00
### Live Demo
This example fills `localStorage` with 10 random keys and 10 random values,
generates a worksheet from the data and writes to a new file.
<details>
<summary><b>Live Demo</b> (click to show)</summary>
2023-09-18 06:44:33 +00:00
2023-04-09 21:13:24 +00:00
```jsx live
function SheetJSRandomStorage() {
const [out, setOut] = React.useState("");
const [rows, setRows] = React.useState([]);
const xport = React.useCallback(async() => {
// reset and populate localStorage
localStorage.clear();
var data = [];
for(let i = 0, last = 0; i < 10; ++i) {
var k = ((Math.random() * 20)|0) + last;
var v = (Math.random() * 16777216).toString(36);
localStorage.setItem(k, v);
data.push([k,v]);
last = k;
}
setRows(Object.entries(localStorage));
// create new worksheet from localStorage
const aoa = Object.entries(localStorage);
const new_ws = XLSX.utils.aoa_to_sheet(aoa);
// create and export workbook
const new_wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(new_wb, new_ws, "Sheet1");
XLSX.writeFile(new_wb, "SheetJSRandomStorage.xlsx");
});
return ( <>
{out && ( <><a href={url}>{url}</a><pre>{out}</pre></> )}
{rows.length && (<table><tr><th>Key</th><th>Value</th></tr>
{rows.map(([k,v]) => (<tr><td>{k}</td><td>{v}</td></tr>))}
</table>) || null}
<br/><button onClick={xport}><b>Export!</b></button>
</> );
}
```
2023-09-18 06:44:33 +00:00
</details>