forked from sheetjs/docs.sheetjs.com
		
	synthetic-dom
This commit is contained in:
		
							parent
							
								
									096b5ddce8
								
							
						
					
					
						commit
						4db5b76501
					
				@ -484,8 +484,14 @@ The data is in the workbook and can be exported.
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
There are multiple opportunities for improvement: the headers can be renamed and
 | 
			
		||||
the column widths can be adjusted.  [SheetJS Pro](https://sheetjs.com/pro) offers
 | 
			
		||||
additional styling options like cell styling and frozen rows.
 | 
			
		||||
the column widths can be adjusted.
 | 
			
		||||
 | 
			
		||||
:::tip pass
 | 
			
		||||
 | 
			
		||||
[SheetJS Pro](https://sheetjs.com/pro) offers additional styling options like
 | 
			
		||||
cell styling and frozen rows.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
<details><summary><b>Changing Header Names</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
@ -957,10 +963,17 @@ of the React Native documentation before testing the demo.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
:::caution pass
 | 
			
		||||
 | 
			
		||||
For Android testing, React Native requires Java 11. It will not work with
 | 
			
		||||
current Java releases.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
Create a new project by running the following commands in the Terminal:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
npx react-native@0.71 init SheetJSPres --version="0.72.0-rc.1"
 | 
			
		||||
npx -y react-native@0.72.4 init SheetJSPres --version="0.72.4"
 | 
			
		||||
cd SheetJSPres
 | 
			
		||||
\n\
 | 
			
		||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz react-native-blob-util@0.17.1`}
 | 
			
		||||
 | 
			
		||||
@ -1266,7 +1266,7 @@ Access `http://localhost:8080` in your web browser and click the export button.
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
:::note pass
 | 
			
		||||
 | 
			
		||||
The [Vite section of the Content demo](/docs/demos/static/vitejs) covers asset
 | 
			
		||||
loaders. They are ideal for static sites pulling data from sheets at build time.
 | 
			
		||||
 | 
			
		||||
@ -5,10 +5,16 @@ title: Synthetic DOM
 | 
			
		||||
import current from '/version.js';
 | 
			
		||||
import CodeBlock from '@theme/CodeBlock';
 | 
			
		||||
 | 
			
		||||
`table_to_book` / `table_to_sheet` / `sheet_add_dom` act on HTML DOM elements.
 | 
			
		||||
Traditionally there is no DOM in server-side environments.
 | 
			
		||||
SheetJS offers three methods to directly process HTML DOM TABLE elements[^1]:
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
- `table_to_sheet` generates a SheetJS worksheet[^2] from a TABLE element
 | 
			
		||||
- `table_to_book` generates a SheetJS workbook[^3] from a TABLE element
 | 
			
		||||
- `sheet_add_dom` adds data from a TABLE element to an existing worksheet
 | 
			
		||||
 | 
			
		||||
These methods work in the web browser. NodeJS and other server-side platforms
 | 
			
		||||
traditionally lack a DOM implementation, but third-party modules fill the gap.
 | 
			
		||||
 | 
			
		||||
:::tip pass
 | 
			
		||||
 | 
			
		||||
The most robust approach for server-side processing is to automate a headless
 | 
			
		||||
web browser. ["Browser Automation"](/docs/demos/net/headless) includes demos.
 | 
			
		||||
@ -17,23 +23,60 @@ web browser. ["Browser Automation"](/docs/demos/net/headless) includes demos.
 | 
			
		||||
 | 
			
		||||
This demo covers synthetic DOM implementations for non-browser platforms.
 | 
			
		||||
 | 
			
		||||
## Integration Details
 | 
			
		||||
 | 
			
		||||
SheetJS API methods use DOM features that may not be available.
 | 
			
		||||
 | 
			
		||||
### Table rows
 | 
			
		||||
 | 
			
		||||
The `rows` property of TABLE elements is a list of TR row children. This list
 | 
			
		||||
automatically updates when rows are added and deleted.
 | 
			
		||||
 | 
			
		||||
SheetJS does not mutate `rows`. Assuming there are no nested tables, the `rows`
 | 
			
		||||
property can be created using `getElementsByTagName`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
tbl.rows = Array.from(tbl.getElementsByTagName("tr"));
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Row cells
 | 
			
		||||
 | 
			
		||||
The `cells` property of TR elements is a list of TD cell children. This list
 | 
			
		||||
automatically updates when cells are added and deleted.
 | 
			
		||||
 | 
			
		||||
SheetJS does not mutate `cells`. Assuming there are no nested tables, the
 | 
			
		||||
`cells` property can be created using `getElementsByTagName`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
tbl.rows.forEach(row => row.cells = Array.from(row.getElementsByTagName("td")));
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## NodeJS
 | 
			
		||||
 | 
			
		||||
### JSDOM
 | 
			
		||||
 | 
			
		||||
JSDOM is a DOM implementation for NodeJS. Given an HTML string, a reference to
 | 
			
		||||
the table element plays nice with the SheetJS DOM methods:
 | 
			
		||||
JSDOM is a DOM implementation for NodeJS. The synthetic DOM elements are
 | 
			
		||||
compatible with SheetJS methods.
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
The following example scrapes the first table from the file `SheetJSTable.html`
 | 
			
		||||
and generates a XLSX workbook:
 | 
			
		||||
 | 
			
		||||
```js title="SheetJSDOM.js"
 | 
			
		||||
const XLSX = require("xlsx");
 | 
			
		||||
const { readFileSync } = require("fs");
 | 
			
		||||
const { JSDOM } = require("jsdom");
 | 
			
		||||
 | 
			
		||||
/* parse HTML */
 | 
			
		||||
const dom = new JSDOM(html_string);
 | 
			
		||||
/* obtain HTML string.  This example reads from SheetJSTable.html */
 | 
			
		||||
const html_str = readFileSync("SheetJSTable.html", "utf8");
 | 
			
		||||
 | 
			
		||||
// highlight-start
 | 
			
		||||
/* get first TABLE element */
 | 
			
		||||
const tbl = dom.window.document.querySelector("table");
 | 
			
		||||
const doc = new JSDOM(html_str).window.document.querySelector("table");
 | 
			
		||||
 | 
			
		||||
/* generate workbook */
 | 
			
		||||
const workbook = XLSX.utils.table_to_book(tbl);
 | 
			
		||||
const workbook = XLSX.utils.table_to_book(doc);
 | 
			
		||||
// highlight-end
 | 
			
		||||
 | 
			
		||||
XLSX.writeFile(workbook, "SheetJSDOM.xlsx");
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -41,7 +84,7 @@ XLSX.writeFile(workbook, "SheetJSDOM.xlsx");
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
This demo was last tested on 2023 May 18 against JSDOM `22.0.0`
 | 
			
		||||
This demo was last tested on 2023 September 10 against JSDOM `22.1.0`
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
@ -51,21 +94,7 @@ This demo was last tested on 2023 May 18 against JSDOM `22.0.0`
 | 
			
		||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz jsdom@22.0.0`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
2) Save the following script to `SheetJSDOM.js`:
 | 
			
		||||
 | 
			
		||||
```js title="SheetJSDOM.js"
 | 
			
		||||
const XLSX = require("xlsx");
 | 
			
		||||
const { readFileSync } = require("fs");
 | 
			
		||||
const { JSDOM } = require("jsdom");
 | 
			
		||||
 | 
			
		||||
/* obtain HTML string.  This example reads from SheetJSTable.html */
 | 
			
		||||
const html_str = readFileSync("SheetJSTable.html", "utf8");
 | 
			
		||||
/* get first TABLE element */
 | 
			
		||||
const doc = new JSDOM(html_str).window.document.querySelector("table");
 | 
			
		||||
/* generate workbook */
 | 
			
		||||
const workbook = XLSX.utils.table_to_book(doc);
 | 
			
		||||
XLSX.writeFile(workbook, "SheetJSDOM.xlsx");
 | 
			
		||||
```
 | 
			
		||||
2) Save the previous codeblock to `SheetJSDOM.js`.
 | 
			
		||||
 | 
			
		||||
3) Download [the sample `SheetJSTable.html`](pathname:///dom/SheetJSTable.html):
 | 
			
		||||
 | 
			
		||||
@ -83,48 +112,79 @@ The script will create a file `SheetJSDOM.xlsx` that can be opened.
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
### XMLDOM
 | 
			
		||||
### HappyDOM
 | 
			
		||||
 | 
			
		||||
XMLDOM provides a DOM framework for NodeJS. Given an HTML string, a reference to
 | 
			
		||||
the table element works with the SheetJS DOM methods after patching the object.
 | 
			
		||||
HappyDOM provides a DOM framework for NodeJS. For the tested version (`11.0.2`),
 | 
			
		||||
the following patches were needed:
 | 
			
		||||
 | 
			
		||||
- TABLE `rows` property (explained above)
 | 
			
		||||
- TR `cells` property (explained above)
 | 
			
		||||
 | 
			
		||||
<details><summary><b>Complete Demo</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
This demo was last tested on 2023 May 18 against XMLDOM `0.8.7`
 | 
			
		||||
This demo was last tested on 2023 September 10 against HappyDOM `11.0.2`
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
1) Install SheetJS and HappyDOM libraries:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz happy-dom@11.0.2`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
2) Download [the sample script `SheetJSHappyDOM.js`](pathname:///dom/SheetJSHappyDOM.js):
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://docs.sheetjs.com/dom/SheetJSHappyDOM.js
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
3) Run the script:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
node SheetJSHappyDOM.js
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The script will create a file `SheetJSHappyDOM.xlsx` that can be opened.
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
### XMLDOM
 | 
			
		||||
 | 
			
		||||
XMLDOM provides a DOM framework for NodeJS. For the tested version (`0.8.10`),
 | 
			
		||||
the following patches were needed:
 | 
			
		||||
 | 
			
		||||
- TABLE `rows` property (explained above)
 | 
			
		||||
- TR `cells` property (explained above)
 | 
			
		||||
- Element `innerHTML` property:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
Object.defineProperty(tbl.__proto__, "innerHTML", { get: function() {
 | 
			
		||||
	var outerHTML = new XMLSerializer().serializeToString(this);
 | 
			
		||||
	if(outerHTML.match(/</g).length == 1) return "";
 | 
			
		||||
	return outerHTML.slice(0, outerHTML.lastIndexOf("</")).replace(/<[^"'>]*(("[^"]*"|'[^']*')[^"'>]*)*>/, "");
 | 
			
		||||
}});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
<details><summary><b>Complete Demo</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
This demo was last tested on 2023 September 10 against XMLDOM `0.8.10`
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
1) Install SheetJS and XMLDOM libraries:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @xmldom/xmldom@0.8.7`}
 | 
			
		||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @xmldom/xmldom@0.8.10`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
2) Save the following codeblock to `SheetJSXMLDOM.js`:
 | 
			
		||||
2) Download [the sample script `SheetJSXMLDOM.js`](pathname:///dom/SheetJSXMLDOM.js):
 | 
			
		||||
 | 
			
		||||
```js title="SheetJSXMLDOM.js"
 | 
			
		||||
const XLSX = require("xlsx");
 | 
			
		||||
const { DOMParser, XMLSerializer } = require("@xmldom/xmldom");
 | 
			
		||||
 | 
			
		||||
(async() => {
 | 
			
		||||
const text = await (await fetch('https://docs.sheetjs.com/dom/SheetJSTable.html')).text();
 | 
			
		||||
const doc = new DOMParser().parseFromString( text, "text/html");
 | 
			
		||||
const tbl = doc.getElementsByTagName("table")[0];
 | 
			
		||||
 | 
			
		||||
/* patch XMLDOM */
 | 
			
		||||
tbl.rows = Array.from(tbl.getElementsByTagName("tr"));
 | 
			
		||||
tbl.rows.forEach(row => row.cells = Array.from(row.getElementsByTagName("td")))
 | 
			
		||||
Object.defineProperty(tbl.__proto__, "innerHTML", { get: function() {
 | 
			
		||||
	var outerHTML = new XMLSerializer().serializeToString(this);
 | 
			
		||||
	if(outerHTML.match(/</g).length == 1) return "";
 | 
			
		||||
	return outerHTML.slice(0, outerHTML.lastIndexOf("</")).replace(/<[^"'>]*(("[^"]*"|'[^']*')[^"'>]*)*>/, "");
 | 
			
		||||
}});
 | 
			
		||||
 | 
			
		||||
const workbook = XLSX.utils.table_to_book(tbl);
 | 
			
		||||
XLSX.writeFile(workbook, "SheetJSXMLDOM.xlsx");
 | 
			
		||||
})();
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://docs.sheetjs.com/dom/SheetJSXMLDOM.js
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
3) Run the script:
 | 
			
		||||
@ -135,28 +195,26 @@ node SheetJSXMLDOM.js
 | 
			
		||||
 | 
			
		||||
The script will create a file `SheetJSXMLDOM.xlsx` that can be opened.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
### CheerioJS
 | 
			
		||||
 | 
			
		||||
:::caution
 | 
			
		||||
:::caution pass
 | 
			
		||||
 | 
			
		||||
Cheerio does not support a number of fundamental properties out of the box. They
 | 
			
		||||
can be shimmed, but it is strongly recommended to use a more compliant library.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
CheerioJS provides a DOM-like framework for NodeJS. Given an HTML string, a
 | 
			
		||||
reference to the table element works with the SheetJS DOM methods with some
 | 
			
		||||
prototype fixes. [`SheetJSCheerio.js`](pathname:///dom/SheetJSCheerio.js) is a
 | 
			
		||||
complete script.
 | 
			
		||||
CheerioJS provides a DOM-like framework for NodeJS. Many features were missing.
 | 
			
		||||
[`SheetJSCheerio.js`](pathname:///dom/SheetJSCheerio.js) implements the missing
 | 
			
		||||
features to ensure that SheetJS DOM methods can process TABLE elements.
 | 
			
		||||
 | 
			
		||||
<details><summary><b>Complete Demo</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
This demo was last tested on 2023 May 18 against Cheerio `1.0.0-rc.12`
 | 
			
		||||
This demo was last tested on 2023 September 10 against Cheerio `1.0.0-rc.12`
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
@ -192,8 +250,11 @@ The script will create a file `SheetJSCheerio.xlsx` that can be opened.
 | 
			
		||||
 | 
			
		||||
### DenoDOM
 | 
			
		||||
 | 
			
		||||
DenoDOM provides a DOM framework for Deno. Given an HTML string, a reference to
 | 
			
		||||
the table element works with the SheetJS DOM methods after patching the object.
 | 
			
		||||
DenoDOM provides a DOM framework for Deno. For the tested version (`0.1.38`),
 | 
			
		||||
the following patches were needed:
 | 
			
		||||
 | 
			
		||||
- TABLE `rows` property (explained above)
 | 
			
		||||
- TR `cells` property (explained above)
 | 
			
		||||
 | 
			
		||||
This example fetches [a sample table](pathname:///dom/SheetJSTable.html):
 | 
			
		||||
 | 
			
		||||
@ -220,11 +281,11 @@ const workbook = XLSX.utils.table_to_book(tbl);
 | 
			
		||||
XLSX.writeFile(workbook, "SheetJSDenoDOM.xlsx");`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
<details open><summary><b>Complete Demo</b> (click to hide)</summary>
 | 
			
		||||
<details><summary><b>Complete Demo</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
This demo was last tested on 2023 May 18 against DenoDOM `0.1.38`
 | 
			
		||||
This demo was last tested on 2023 September 10 against DenoDOM `0.1.38`
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
@ -238,4 +299,8 @@ deno run --allow-net --allow-write SheetJSDenoDOM.ts
 | 
			
		||||
 | 
			
		||||
The script will create a file `SheetJSDenoDOM.xlsx` that can be opened.
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
[^1]: See ["HTML Table Input" in "Utilities"](/docs/api/utilities/html#html-table-input)
 | 
			
		||||
[^2]: See ["Worksheet Object" in "SheetJS Data Model"](/docs/csf/book) for more details.
 | 
			
		||||
[^3]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details.
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,7 @@
 | 
			
		||||
---
 | 
			
		||||
title: Ionic
 | 
			
		||||
title: Data Conduction in Ionic Apps
 | 
			
		||||
sidebar_label: Ionic
 | 
			
		||||
description: Build data-intensive mobile apps with Ionic and Cordova. Seamlessly integrate spreadsheets into your app using SheetJS. Let data in your Excel spreadsheets shine.
 | 
			
		||||
pagination_prev: demos/static/index
 | 
			
		||||
pagination_next: demos/desktop/index
 | 
			
		||||
sidebar_position: 4
 | 
			
		||||
@ -10,10 +12,17 @@ sidebar_custom_props:
 | 
			
		||||
import current from '/version.js';
 | 
			
		||||
import CodeBlock from '@theme/CodeBlock';
 | 
			
		||||
 | 
			
		||||
The [NodeJS Module](/docs/getting-started/installation/nodejs) can be imported
 | 
			
		||||
from the main entrypoint or any script in the project.
 | 
			
		||||
[Ionic](https://ionicframework.com/) is a mobile app framework for building iOS
 | 
			
		||||
and Android apps with the Cordova platform.
 | 
			
		||||
 | 
			
		||||
The "Complete Example" creates an app that looks like the screenshots below:
 | 
			
		||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
 | 
			
		||||
data from spreadsheets.
 | 
			
		||||
 | 
			
		||||
This demo uses Ionic and SheetJS to process data and generate spreadsheets.
 | 
			
		||||
We'll explore how to load SheetJS in an Ionic app and use Ionic APIs and plugins
 | 
			
		||||
to extract data from, and write data to, spreadsheet files on the device.
 | 
			
		||||
 | 
			
		||||
The ["Demo"](#demo) creates an app that looks like the screenshots below:
 | 
			
		||||
 | 
			
		||||
<table><thead><tr>
 | 
			
		||||
  <th><a href="#demo">iOS</a></th>
 | 
			
		||||
@ -28,6 +37,13 @@ The "Complete Example" creates an app that looks like the screenshots below:
 | 
			
		||||
 | 
			
		||||
</td></tr></tbody></table>
 | 
			
		||||
 | 
			
		||||
:::info pass
 | 
			
		||||
 | 
			
		||||
This demo covers Ionic apps using the Cordova platform.
 | 
			
		||||
 | 
			
		||||
The [CapacitorJS demo](/docs/demos/mobile/capacitor) covers CapacitorJS apps.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
:::warning Telemetry
 | 
			
		||||
 | 
			
		||||
@ -57,18 +73,36 @@ npx @capacitor/cli telemetry
 | 
			
		||||
 | 
			
		||||
## Integration Details
 | 
			
		||||
 | 
			
		||||
:::caution pass
 | 
			
		||||
The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be
 | 
			
		||||
imported from the main entrypoint or any script in the project.
 | 
			
		||||
 | 
			
		||||
The latest version of Ionic uses CapacitorJS. These notes are for Cordova apps.
 | 
			
		||||
The [CapacitorJS demo](/docs/demos/mobile/capacitor) covers CapacitorJS apps.
 | 
			
		||||
### Internal State
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
The ["Angular" demo](/docs/demos/frontend/angular) discusses a number of state
 | 
			
		||||
representations and preview strategies.
 | 
			
		||||
 | 
			
		||||
### Angular
 | 
			
		||||
For this demo, the internal state is an "array of arrays"[^1] (`any[][]`):
 | 
			
		||||
 | 
			
		||||
`Array<Array<any>>` neatly maps to a table with `ngFor`:
 | 
			
		||||
```ts title="Array of Arrays state"
 | 
			
		||||
import { Component } from '@angular/core';
 | 
			
		||||
type AOA = any[][];
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
@Component({...})
 | 
			
		||||
export class SheetJSTablePage {
 | 
			
		||||
  data: AOA = [
 | 
			
		||||
    ["S", "h", "e", "e", "t", "J", "S"],
 | 
			
		||||
    [  5,   4,   3,   3,   7,   9,   5]
 | 
			
		||||
  ];
 | 
			
		||||
  // ...
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Displaying Data
 | 
			
		||||
 | 
			
		||||
`ion-grid`[^2] is a display grid component. The Angular `ngFor` directive[^3]
 | 
			
		||||
simplifies iteration over the array of arrays:
 | 
			
		||||
 | 
			
		||||
```html title="Template for displaying an array of arrays"
 | 
			
		||||
<ion-grid>
 | 
			
		||||
  <ion-row *ngFor="let row of data">
 | 
			
		||||
    <ion-col *ngFor="let val of row">
 | 
			
		||||
@ -78,29 +112,62 @@ The [CapacitorJS demo](/docs/demos/mobile/capacitor) covers CapacitorJS apps.
 | 
			
		||||
</ion-grid>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Cordova
 | 
			
		||||
### File Operations
 | 
			
		||||
 | 
			
		||||
`@ionic-native/file` reads and writes files on devices.
 | 
			
		||||
`@awesome-cordova-plugins/file` reads and writes files on devices.
 | 
			
		||||
 | 
			
		||||
_Reading Files_
 | 
			
		||||
:::info pass
 | 
			
		||||
 | 
			
		||||
`readAsArrayBuffer` returns `ArrayBuffer` objects suitable for `array` type:
 | 
			
		||||
The plugins in the `@ionic-native` scope have been deprecated. The community
 | 
			
		||||
modules in the `@awesome-cordova-plugins` scope should be used.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
#### Reading Files
 | 
			
		||||
 | 
			
		||||
`this.file.readAsArrayBuffer` reads file data from a specified URL and resolves
 | 
			
		||||
to `ArrayBuffer` objects.
 | 
			
		||||
 | 
			
		||||
These objects can be parsed with the SheetJS `read` method[^4]. The SheetJS
 | 
			
		||||
`sheet_to_json` method[^5] with the option `header: 1` generates an array of
 | 
			
		||||
arrays which can be assigned to the page state:
 | 
			
		||||
 | 
			
		||||
```ts
 | 
			
		||||
/* read a workbook */
 | 
			
		||||
/* read a workbook file */
 | 
			
		||||
const ab: ArrayBuffer = await this.file.readAsArrayBuffer(url, filename);
 | 
			
		||||
/* parse */
 | 
			
		||||
const wb: XLSX.WorkBook = XLSX.read(ab, {type: 'array'});
 | 
			
		||||
/* generate an array of arrays from the first worksheet */
 | 
			
		||||
const ws: XLSX.WorkSheet = wb.SheetNames[wb.Sheets[0]];
 | 
			
		||||
const aoa: AOA = XLSX.utils.sheet_to_json(ws, {header: 1});
 | 
			
		||||
/* update state */
 | 
			
		||||
this.data = aoa;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
_Writing Files_
 | 
			
		||||
#### Writing Files
 | 
			
		||||
 | 
			
		||||
`array` type can be converted to blobs that can be exported with `writeFile`:
 | 
			
		||||
`this.file.writeFile` writes file data stored in `Blob` objects to the device.
 | 
			
		||||
 | 
			
		||||
From the array of arrays, the SheetJS `aoa_to_sheet` method[^6] generates a
 | 
			
		||||
worksheet object. The `book_new` and `book_append_sheet` helpers[^7] generate a
 | 
			
		||||
workbook object. The SheetJS `write` method[^8] with the option `type: "array"`
 | 
			
		||||
will generate an `ArrayBuffer`, from which a `Blob` can be created:
 | 
			
		||||
 | 
			
		||||
```ts
 | 
			
		||||
/* write a workbook */
 | 
			
		||||
const wbout: ArrayBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
 | 
			
		||||
let blob = new Blob([wbout], {type: 'application/octet-stream'});
 | 
			
		||||
/* generate worksheet */
 | 
			
		||||
const ws: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(this.data);
 | 
			
		||||
 | 
			
		||||
/* generate workbook and add the worksheet */
 | 
			
		||||
const wb: XLSX.WorkBook = XLSX.utils.book_new();
 | 
			
		||||
XLSX.utils.book_append_sheet(wb, ws, 'SheetJS');
 | 
			
		||||
 | 
			
		||||
/* write XLSX to ArrayBuffer */
 | 
			
		||||
const ab: ArrayBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
 | 
			
		||||
 | 
			
		||||
/* generate Blob */
 | 
			
		||||
let blob = new Blob([ab], {type: 'application/octet-stream'});
 | 
			
		||||
 | 
			
		||||
/* write Blob to device */
 | 
			
		||||
this.file.writeFile(url, filename, blob, {replace: true});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -108,47 +175,72 @@ this.file.writeFile(url, filename, blob, {replace: true});
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
This demo was tested on an Intel Mac on 2023 March 28 with Cordova.
 | 
			
		||||
The file integration uses `@ionic-native/file` version `5.36.0`.
 | 
			
		||||
The project was last tested in 2023 September 10. `ionic info` showed:
 | 
			
		||||
 | 
			
		||||
The iOS simulator runs iOS 15.5 on an iPhone SE (3rd Generation).
 | 
			
		||||
- Ionic: `@ionic/angular 7.3.3`, `@ionic/angular-toolkit 9.0.0`
 | 
			
		||||
- Cordova: `cordova-lib@12.0.1`, `android 12.0.1, ios 7.0.1`
 | 
			
		||||
 | 
			
		||||
The Android simulator runs Android 12.0 (S) API 31 on a Pixel 3.
 | 
			
		||||
The file integration uses `@awesome-cordova-plugins/file` version `6.4.0`.
 | 
			
		||||
 | 
			
		||||
The iOS demo was last tested on 2023 September 10 on an emulated iPhone SE
 | 
			
		||||
(3rd generation) + iOS 16.4
 | 
			
		||||
 | 
			
		||||
The Android demo was last tested on 2023 September 10 on an emulated Pixel 3 +
 | 
			
		||||
Android 13 ("Tiramisu") API 33.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
The app in this demo will display data in a table.
 | 
			
		||||
 | 
			
		||||
On load, a [test file](https://sheetjs.com/pres.numbers) will be processed.
 | 
			
		||||
 | 
			
		||||
When a document is selected with the file picker, it will be processed and the
 | 
			
		||||
table will refresh to show the contents.
 | 
			
		||||
 | 
			
		||||
"Import Data" will attempt to read `SheetJSIonic.xlsx` from a known location. An
 | 
			
		||||
alert will display the expected location.
 | 
			
		||||
 | 
			
		||||
"Export Data" will attempt to export the table data to `SheetJSIonic.xlsx` in a
 | 
			
		||||
known location. After writing, an alert will display the location of the file.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Platform Setup
 | 
			
		||||
 | 
			
		||||
0) Disable telemetry as noted in the warning.
 | 
			
		||||
 | 
			
		||||
Install required global dependencies:
 | 
			
		||||
1) Follow the official instructions for iOS and Android development[^9].
 | 
			
		||||
 | 
			
		||||
2) Install required global dependencies:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm i -g cordova-res @angular/cli native-run @ionic/cli
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Follow the [React Native demo](/docs/demos/mobile/reactnative) to ensure iOS and Android sims are ready.
 | 
			
		||||
### Base Project
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
1) Create a new project:
 | 
			
		||||
3) Create a new project:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
ionic start SheetJSIonic blank --type angular --cordova --quiet --no-git --no-link --confirm
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
When asked to select `NgModules` or `Standalone Components`, select `NgModules`
 | 
			
		||||
 | 
			
		||||
If a prompt asks to confirm Cordova use, enter `Yes` to continue.
 | 
			
		||||
 | 
			
		||||
If a prompt asks about creating an Ionic account, enter `N` to opt out.
 | 
			
		||||
 | 
			
		||||
2) Set up Cordova:
 | 
			
		||||
4) Set up Cordova:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
cd SheetJSIonic
 | 
			
		||||
ionic cordova plugin add cordova-plugin-file
 | 
			
		||||
ionic cordova platform add ios --confirm
 | 
			
		||||
ionic cordova platform add android --confirm
 | 
			
		||||
npm i --save @ionic-native/core @ionic-native/file @ionic/cordova-builders
 | 
			
		||||
npm i --save @awesome-cordova-plugins/core @awesome-cordova-plugins/file @ionic/cordova-builders
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
:::note pass
 | 
			
		||||
 | 
			
		||||
If `cordova-plugin-file` is added before the platforms, installation may fail:
 | 
			
		||||
 | 
			
		||||
@ -165,9 +257,9 @@ ionic cordova platform add ios --confirm
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
:::caution
 | 
			
		||||
:::caution pass
 | 
			
		||||
 | 
			
		||||
If the `npm i` fails due to `rxjs` resolution, add the highlighted lines
 | 
			
		||||
If the `npm i` step fails due to `rxjs` resolution, add the highlighted lines
 | 
			
		||||
to `package.json` to force a resolution:
 | 
			
		||||
 | 
			
		||||
```js title="package.json"
 | 
			
		||||
@ -180,24 +272,26 @@ to `package.json` to force a resolution:
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Note that the required `rxjs` version will be displayed in the error log.
 | 
			
		||||
 | 
			
		||||
After adding the lines, the `npm i` command will succeed.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
3) Install dependencies:
 | 
			
		||||
5) Install dependencies:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
4) Add `@ionic-native/file` to the module.  Differences highlighted below:
 | 
			
		||||
6) Add `@awesome-cordova-plugins/file` to the module.  Differences highlighted below:
 | 
			
		||||
 | 
			
		||||
```ts title="src/app/app.module.ts"
 | 
			
		||||
import { AppComponent } from './app.component';
 | 
			
		||||
import { AppRoutingModule } from './app-routing.module';
 | 
			
		||||
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
import { File } from '@ionic-native/file/ngx';
 | 
			
		||||
import { File } from '@awesome-cordova-plugins/file/ngx';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: [AppComponent],
 | 
			
		||||
@ -210,19 +304,41 @@ import { File } from '@ionic-native/file/ngx';
 | 
			
		||||
export class AppModule {}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
5) Download [`home.page.ts`](pathname:///ionic/home.page.ts) and replace:
 | 
			
		||||
7) Download [`home.page.ts`](pathname:///ionic/home.page.ts) and replace:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -o src/app/home/home.page.ts -L https://docs.sheetjs.com/ionic/home.page.ts
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**iOS Testing**
 | 
			
		||||
### iOS
 | 
			
		||||
 | 
			
		||||
8) Enable file sharing and make the documents folder visible in the iOS app.
 | 
			
		||||
Add the following lines to `platforms/ios/SheetJSIonic/SheetJSIonic-Info.plist`:
 | 
			
		||||
 | 
			
		||||
```xml title="platforms/ios/SheetJSIonic/SheetJSIonic-Info.plist (add to file)"
 | 
			
		||||
<plist version="1.0">
 | 
			
		||||
<dict>
 | 
			
		||||
<!-- highlight-start -->
 | 
			
		||||
  <key>UIFileSharingEnabled</key>
 | 
			
		||||
  <true/>
 | 
			
		||||
  <key>LSSupportsOpeningDocumentsInPlace</key>
 | 
			
		||||
  <true/>
 | 
			
		||||
<!-- highlight-end -->
 | 
			
		||||
  <key>CFBundleDevelopmentRegion</key>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
(The root element of the document is `plist` and it contains one `dict` child)
 | 
			
		||||
 | 
			
		||||
9) Build the app and start the simulator
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
ionic cordova emulate ios
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::caution
 | 
			
		||||
When the app is loaded, a list of Presidents should be displayed. This list is
 | 
			
		||||
dynamically generated by fetching and parsing a test file.
 | 
			
		||||
 | 
			
		||||
:::caution pass
 | 
			
		||||
 | 
			
		||||
In some test runs, the `cordova build ios --emulator` step failed with error:
 | 
			
		||||
 | 
			
		||||
@ -239,13 +355,54 @@ npm i --save cordova-ios
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
**Android Testing**
 | 
			
		||||
:::info pass
 | 
			
		||||
 | 
			
		||||
In the most recent test, the `native-run ios` command failed with
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
[native-run] ERR_UNKNOWN: Path 'platforms/ios/build/emulator/SheetJSIonic.app' not found
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Inspecting `platforms/ios/build/`, the actual folder name was:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
% ls platforms/ios/build
 | 
			
		||||
#highlight-next-line
 | 
			
		||||
Debug-iphonesimulator
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The iOS simulator can be launched manually:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
native-run ios --app platforms/ios/build/Debug-iphonesimulator/SheetJSIonic.app --virtual
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
### Android
 | 
			
		||||
 | 
			
		||||
10) Enable file reading and writing in the Android app.
 | 
			
		||||
 | 
			
		||||
Edit `platforms/android/app/src/main/AndroidManifest.xml` and add the following
 | 
			
		||||
two lines before the `application` tag:
 | 
			
		||||
 | 
			
		||||
```xml title="platforms/android/app/src/main/AndroidManifest.xml (add to file)"
 | 
			
		||||
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
In the `application` tag, add the attribute `android:requestLegacyExternalStorage="true"`.
 | 
			
		||||
 | 
			
		||||
11) Build the app and start the emulator
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
ionic cordova emulate android
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::caution
 | 
			
		||||
When the app is loaded, a list of Presidents should be displayed. This list is
 | 
			
		||||
dynamically generated by fetching and parsing a test file.
 | 
			
		||||
 | 
			
		||||
:::caution pass
 | 
			
		||||
 | 
			
		||||
In some test runs, `cordova build android --emulator` step failed with error:
 | 
			
		||||
 | 
			
		||||
@ -260,3 +417,40 @@ npm i --save cordova-android
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
:::caution pass
 | 
			
		||||
 | 
			
		||||
In some tests, the build failed with a Gradle error:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
Could not find an installed version of Gradle either in Android Studio,
 | 
			
		||||
or on your system to install the gradle wrapper. Please include gradle
 | 
			
		||||
in your path or install Android Studio
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
On macOS, this issue was resolved by installing gradle with Homebrew manager:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
brew install gradle
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
:::warning pass
 | 
			
		||||
 | 
			
		||||
When the demo was last tested on Android, reading files worked as expected.
 | 
			
		||||
However, the generated files were not externally visible from the Files app.
 | 
			
		||||
 | 
			
		||||
**This is a known bug with Android SDK 33 and the underlying file plugins!**
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
[^1]: See ["Array of Arrays" in the API reference](/docs/api/utilities/array#array-of-arrays)
 | 
			
		||||
[^2]: See [`ion-grid`](https://ionicframework.com/docs/api/grid) in the Ionic documentation.
 | 
			
		||||
[^3]: See [`ngFor`](https://angular.io/api/common/NgFor) in the Angular documentation.
 | 
			
		||||
[^4]: See [`read` in "Reading Files"](/docs/api/parse-options)
 | 
			
		||||
[^5]: See ["Array Output" in "Utility Functions"](/docs/api/utilities/array#array-output)
 | 
			
		||||
[^6]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input)
 | 
			
		||||
[^7]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
 | 
			
		||||
[^8]: See [`write` in "Writing Files"](/docs/api/write-options)
 | 
			
		||||
[^9]: See ["Developing for iOS"](https://ionicframework.com/docs/v6/developing/ios) and ["Developing for Android"](https://ionicframework.com/docs/v6/developing/android) in the v6 Ionic framework documentation.
 | 
			
		||||
@ -200,7 +200,7 @@ after the `Permissions` comment:
 | 
			
		||||
 | 
			
		||||
<!-- highlight-start -->
 | 
			
		||||
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
 | 
			
		||||
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 | 
			
		||||
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 | 
			
		||||
<!-- highlight-end -->
 | 
			
		||||
 | 
			
		||||
    <uses-permission android:name="android.permission.INTERNET" />
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								docz/static/dom/SheetJSDOM.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										11
									
								
								docz/static/dom/SheetJSDOM.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
const XLSX = require("xlsx");
 | 
			
		||||
const { readFileSync } = require("fs");
 | 
			
		||||
const { JSDOM } = require("jsdom");
 | 
			
		||||
 | 
			
		||||
/* obtain HTML string.  This example reads from SheetJSTable.html */
 | 
			
		||||
const html_str = readFileSync("SheetJSTable.html", "utf8");
 | 
			
		||||
/* get first TABLE element */
 | 
			
		||||
const doc = new JSDOM(html_str).window.document.querySelector("table");
 | 
			
		||||
/* generate workbook */
 | 
			
		||||
const workbook = XLSX.utils.table_to_book(doc);
 | 
			
		||||
XLSX.writeFile(workbook, "SheetJSDOM.xlsx");
 | 
			
		||||
							
								
								
									
										23
									
								
								docz/static/dom/SheetJSHappyDOM.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										23
									
								
								docz/static/dom/SheetJSHappyDOM.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
const XLSX = require("xlsx");
 | 
			
		||||
const { readFileSync } = require("fs");
 | 
			
		||||
const { Window } = require("happy-dom");
 | 
			
		||||
 | 
			
		||||
/* obtain HTML string.  This example reads from SheetJSTable.html */
 | 
			
		||||
const html_str = readFileSync("SheetJSTable.html", "utf8");
 | 
			
		||||
 | 
			
		||||
/* get table element */
 | 
			
		||||
const window = new Window({
 | 
			
		||||
    url: "https://localhost:8080",
 | 
			
		||||
    width: 1024,
 | 
			
		||||
    height: 768
 | 
			
		||||
});
 | 
			
		||||
window.document.body.innerHTML = html_str;
 | 
			
		||||
const tbl = window.document.body.getElementsByTagName("table")[0];
 | 
			
		||||
 | 
			
		||||
/* add `rows` and `cells` properties */
 | 
			
		||||
tbl.rows = Array.from(tbl.getElementsByTagName("tr"));
 | 
			
		||||
tbl.rows.forEach(row => row.cells = Array.from(row.getElementsByTagName("td")))
 | 
			
		||||
 | 
			
		||||
/* generate workbook */
 | 
			
		||||
const workbook = XLSX.utils.table_to_book(tbl);
 | 
			
		||||
XLSX.writeFile(workbook, "SheetJSHappyDOM.xlsx");
 | 
			
		||||
							
								
								
									
										20
									
								
								docz/static/dom/SheetJSXMLDOM.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										20
									
								
								docz/static/dom/SheetJSXMLDOM.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
const XLSX = require("xlsx");
 | 
			
		||||
const { DOMParser, XMLSerializer } = require("@xmldom/xmldom");
 | 
			
		||||
 | 
			
		||||
(async() => {
 | 
			
		||||
const text = await (await fetch('https://docs.sheetjs.com/dom/SheetJSTable.html')).text();
 | 
			
		||||
const doc = new DOMParser().parseFromString( text, "text/html");
 | 
			
		||||
const tbl = doc.getElementsByTagName("table")[0];
 | 
			
		||||
 | 
			
		||||
/* patch XMLDOM */
 | 
			
		||||
tbl.rows = Array.from(tbl.getElementsByTagName("tr"));
 | 
			
		||||
tbl.rows.forEach(row => row.cells = Array.from(row.getElementsByTagName("td")));
 | 
			
		||||
Object.defineProperty(tbl.__proto__, "innerHTML", { get: function() {
 | 
			
		||||
    var outerHTML = new XMLSerializer().serializeToString(this);
 | 
			
		||||
    if(outerHTML.match(/</g).length == 1) return "";
 | 
			
		||||
    return outerHTML.slice(0, outerHTML.lastIndexOf("</")).replace(/<[^"'>]*(("[^"]*"|'[^']*')[^"'>]*)*>/, "");
 | 
			
		||||
}});
 | 
			
		||||
 | 
			
		||||
const workbook = XLSX.utils.table_to_book(tbl);
 | 
			
		||||
XLSX.writeFile(workbook, "SheetJSXMLDOM.xlsx");
 | 
			
		||||
})();
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 46 KiB  | 
@ -1,7 +1,7 @@
 | 
			
		||||
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
 | 
			
		||||
/* vim: set ts=2: */
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { File } from '@ionic-native/file/ngx';
 | 
			
		||||
import { File } from '@awesome-cordova-plugins/file/ngx';
 | 
			
		||||
import * as XLSX from 'xlsx';
 | 
			
		||||
 | 
			
		||||
type AOA = any[][];
 | 
			
		||||
@ -42,7 +42,7 @@ type AOA = any[][];
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export class HomePage implements OnInit {
 | 
			
		||||
  data: any[][] = [[1,2,3],[4,5,6]];
 | 
			
		||||
  data: AOA = [[1,2,3],[4,5,6]];
 | 
			
		||||
  constructor(public file: File) {}
 | 
			
		||||
 | 
			
		||||
  async ngOnInit(): Promise<void> {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user