VBA event handler example

This commit is contained in:
SheetJS 2025-09-03 23:55:16 -04:00
parent 609f7ff5f2
commit ac0f80025a
30 changed files with 119 additions and 47 deletions

@ -321,9 +321,9 @@ interface President { Name: string; Index: number };
<td>{{row.Index}}</td>
</tr>
// highlight-end
</tbody><tfoot>
</tbody><tfoot><tr><td colspan="2">
<button (click)="onSave()">Export XLSX</button>
</tfoot>
</td></tr></tfoot>
</table></div>
`
})
@ -379,9 +379,9 @@ interface President { Name: string; Index: number };
</tr>
}
// highlight-end
</tbody><tfoot>
</tbody><tfoot><tr><td colspan="2">
<button (click)="onSave()">Export XLSX</button>
</tfoot>
</td></tr></tfoot>
</table></div>
`
})
@ -425,6 +425,7 @@ This demo was tested in the following environments:
| Angular | Date |
|:----------|:-----------|
| `20.2.3` | 2025-09-03 |
| `19.0.5` | 2025-01-03 |
| `18.2.13` | 2025-01-03 |
| `17.3.12` | 2025-01-03 |
@ -441,7 +442,7 @@ npx @angular/cli analytics disable -g
1) Create a new project:
```bash
npx @angular/cli@19 new --minimal --defaults --no-interactive sheetjs-angular
npx @angular/cli@20 new --minimal --defaults --no-interactive sheetjs-angular
```
:::note pass
@ -468,8 +469,20 @@ npm start`}
3) Open a web browser and access the displayed URL (`http://localhost:4200`)
4) In the previous `src/app/app.component.ts` code snippet, select the tab for
the appropriate version of Angular ("Angular 2-16" or "Angular 17+"), copy the
code contents and replace `src/app/app.component.ts` in the project.
the appropriate version of Angular ("Angular 2-16" or "Angular 17+") and copy
the code. Replace `src/app/app.component.ts` or `src/app/app.ts` in the project.
For Angular 20+, after replacing `src/app/app.ts`, edit the script and change
the exported class name to `App`:
```ts title="src/app/app.ts (edit highlighted line if file exists)"
// ...
})
// highlight-next-line
export class App {
rows: President[] = [ { Name: "SheetJS", Index: 0 }];
// ...
```
The page will refresh and show a table with an Export button. Click the button
and the page will attempt to download `SheetJSAngularAoO.xlsx`. Open the file

@ -130,7 +130,7 @@ function exportFile() {
<!-- highlight-end -->
</tbody><tfoot><tr><td colSpan={2}>
<button on:click={exportFile}>Export XLSX</button>
</td></tfoot></tr></table>
</td></tr></tfoot></table>
</main>
```
@ -143,7 +143,7 @@ This demo was tested in the following environments:
| SvelteJS | ViteJS | Date |
|:---------|:---------|:-----------|
| `5.25.3` | `6.2.3` | 2025-03-30 |
| `5.38.6` | `7.1.1` | 2025-09-03 |
:::

@ -44,7 +44,7 @@ The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be
imported from the main or the renderer thread.
The SheetJS `readFile` and `writeFile` methods will use the Electron `fs` module
where available.
where available.
<details>
<summary><b>Renderer Configuration</b> (click to show)</summary>
@ -57,6 +57,37 @@ Electron 12 and later also require `worldSafeExecuteJavascript: true` and
</details>
:::caution pass
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
can be loaded from the renderer thread using a standard `SCRIPT` tag, but it is
strongly discouraged.
[Issue 3314](https://git.sheetjs.com/sheetjs/sheetjs/issues/3314) in the SheetJS
CE issue tracker describes the required HTML configuration.
<details>
<summary><b>HTML Configuration</b> (click to show)</summary>
The following CSP directives should be specified in the `HEAD` block:
```html
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.sheetjs.com"
/>
<meta
http-equiv="X-Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.sheetjs.com"
/>
```
Without these settings, newer Electron versions will not run the scripts.
</details>
:::
### Reading Files
Electron offers 3 different ways to read files, two of which use Web APIs.
@ -208,7 +239,7 @@ This demo was tested in the following environments:
| OS and Version | Architecture | Electron | Date |
|:---------------|:-------------|:---------|:-----------|
| macOS 15.3 | `darwin-x64` | `35.1.2` | 2025-03-31 |
| macOS 14.5 | `darwin-arm` | `35.1.2` | 2025-03-30 |
| macOS 14.5 | `darwin-arm` | `35.1.2` | 2025-08-30 |
| Windows 11 | `win11-x64` | `33.2.1` | 2025-02-11 |
| Windows 11 | `win11-arm` | `33.2.1` | 2025-02-23 |
| Linux (Ubuntu) | `linux-x64` | `35.1.2` | 2025-07-06 |

@ -129,7 +129,7 @@ This demo was tested in the following deployments:
| Architecture | Version | Date |
|:-------------|:--------|:-----------|
| `darwin-x64` | `2.7.0` | 2025-03-31 |
| `darwin-arm` | `2.7.0` | 2025-02-13 |
| `darwin-arm` | `2.7.0` | 2025-09-03 |
| `win11-x64` | `2.7.0` | 2025-04-28 |
| `win11-arm` | `2.7.0` | 2025-02-23 |
| `linux-x64` | `2.7.0` | 2025-04-21 |

@ -264,7 +264,7 @@ This demo was tested in the following deployments:
| Architecture | Library | Git Commit | Date |
|:-------------|:-----------|:-----------|:-----------|
| `darwin-x64` | QuickJS | `0d7aaed` | 2025-03-31 |
| `darwin-arm` | QuickJS | `3306254` | 2025-04-24 |
| `darwin-arm` | QuickJS | `3306254` | 2025-09-03 |
| `win11-x64` | QuickJS-NG | `865ba1f` | 2025-04-18 |
| `win11-arm` | QuickJS-NG | `865ba1f` | 2025-04-18 |
| `linux-x64` | QuickJS | `3306254` | 2025-06-18 |

@ -365,7 +365,7 @@ This demo was tested in the following deployments:
| Architecture | Git Commit | Date |
|:-------------|:-----------|:-----------|
| `darwin-x64` | `8ef11b4` | 2025-03-31 |
| `darwin-arm` | `8ef11b4` | 2025-08-07 |
| `darwin-arm` | `8ef11b4` | 2025-09-03 |
| `linux-x64` | `8ef11b4` | 2025-04-21 |
| `linux-arm` | `388376f` | 2025-02-15 |

@ -88,7 +88,7 @@ This demo was tested in the following deployments:
| Platform | Ruby | ExecJS | Date |
|:-------------|:---------|:---------|:-----------|
| `darwin-x64` | `2.6.10` | `2.10.0` | 2025-03-31 |
| `darwin-arm` | `2.6.10` | `2.10.0` | 2025-02-13 |
| `darwin-arm` | `2.6.10` | `2.10.0` | 2025-09-03 |
| `win11-x64` | `3.3.8` | `2.10.0` | 2025-04-28 |
| `win11-arm` | `3.2.3` | `2.10.0` | 2025-02-23 |
| `linux-x64` | `3.2.3` | `2.10.0` | 2025-04-21 |

@ -133,7 +133,7 @@ This demo was tested in the following deployments:
| Architecture | Git Commit | Date |
|:-------------|:-----------|:-----------|
| `darwin-x64` | `36becec` | 2025-03-31 |
| `darwin-arm` | `36becec` | 2025-06-20 |
| `darwin-arm` | `36becec` | 2025-09-03 |
| `win11-x64` | `36becec` | 2025-04-28 |
| `win11-arm` | `e26c81f` | 2025-02-23 |
| `linux-x64` | `36becec` | 2025-06-18 |

@ -105,7 +105,7 @@ This demo was tested in the following deployments:
| Architecture | Boa | Date |
|:-------------|:---------|:-----------|
| `darwin-x64` | `0.20.0` | 2025-03-31 |
| `darwin-arm` | `0.20.0` | 2025-02-13 |
| `darwin-arm` | `0.20.0` | 2025-09-03 |
| `win11-x64` | `0.20.0` | 2025-04-28 |
| `win11-arm` | `0.20.0` | 2025-02-23 |
| `linux-x64` | `0.20.0` | 2025-04-21 |

@ -128,7 +128,7 @@ This demo was tested in the following deployments:
| Architecture | Version | Date |
|:-------------|:--------|:-----------|
| `darwin-x64` | `0.066` | 2025-03-31 |
| `darwin-arm` | `0.066` | 2025-02-13 |
| `darwin-arm` | `0.066` | 2025-09-03 |
| `linux-x64` | `0.066` | 2025-06-16 |
| `linux-arm` | `0.066` | 2025-02-15 |

@ -37,7 +37,7 @@ This demo was tested in the following environments:
| Architecture | Commit | Date |
|:-------------|:----------|:-----------|
| `darwin-x64` | `5020015` | 2025-03-31 |
| `darwin-arm` | `d2d30df` | 2025-02-13 |
| `darwin-arm` | `355ab24` | 2025-09-03 |
| `win11-x64` | `5020015` | 2025-04-23 |
| `win11-arm` | `5020015` | 2025-02-23 |
| `linux-x64` | `5020015` | 2025-04-21 |

@ -323,7 +323,7 @@ This demo was tested in the following deployments:
| Architecture | Version | Date |
|:-------------|:--------|:-----------|
| `darwin-x64` | `1.3.6` | 2025-03-31 |
| `darwin-arm` | `1.3.5` | 2025-02-13 |
| `darwin-arm` | `1.3.6` | 2025-09-03 |
| `win11-x64` | `1.3.6` | 2025-04-23 |
| `win11-arm` | `1.3.5` | 2025-02-23 |
| `linux-x64` | `1.3.6` | 2025-06-16 |

@ -177,7 +177,7 @@ This demo was tested in the following deployments:
| Architecture | Jurassic | Date |
|:-------------|:---------|:-----------|
| `darwin-x64` | `3.2.9` | 2025-03-31 |
| `darwin-arm` | `3.2.9` | 2025-03-30 |
| `darwin-arm` | `3.2.9` | 2025-09-03 |
| `win11-x64` | `3.2.9` | 2025-04-23 |
| `win11-arm` | `3.2.9` | 2025-02-23 |
| `linux-x64` | `3.2.9` | 2025-06-16 |

@ -69,7 +69,9 @@ the VBA project, and exporting new VBA blobs.
## Demos
The export demos focus on [an example](pathname:///vba/SheetJSVBAFormula.xlsm)
that includes the following user-defined functions:
that includes the following macros:
_User-defined functions_
```vb
Function GetFormulaA1(Cell As Range) As String
@ -81,6 +83,13 @@ Function GetFormulaRC(Cell As Range) As String
End Function
```
_Event Handlers_
```vb
Sub Workbook_Open()
MsgBox "Hello from SheetJS!", vbOKOnly
End Sub
```
### Copying Macros
@ -239,34 +248,53 @@ To ensure the writers export the VBA blob:
- The output format must support VBA (`xlsm` or `xlsb` or `xls` or `biff8`)
- The workbook object must have a valid `vbaraw` field
- The option `bookVBA: true` must be passed to `write` or `writeFile`
This example uses [`vbaProject.bin`](pathname:///vba/vbaProject.bin) from the
[sample file](pathname:///vba/SheetJSVBAFormula.xlsm):
[sample file](pathname:///vba/SheetJSVBAFormula.xlsm). When the files are
opened, if macros are enabled, the application will display a popup.
:::note pass
Cells `A2:C2` in the worksheet include formulae that use user-defined functions.
Not all file formats support formula exports. [The "Formulae" page](./formulae)
includes a table of supported file formats.
:::
```jsx live
function SheetJSVBAPrepared() { return ( <button onClick={async () => {
/* Download prepared VBA blob */
const url = "/vba/vbaProject.bin";
const blob = new Uint8Array(await (await fetch(url)).arrayBuffer());
function SheetJSVBAPrepared() {
const exportFile = async (ext) => {
/* Download prepared VBA blob */
const url = "/vba/vbaProject.bin";
const blob = new Uint8Array(await (await fetch(url)).arrayBuffer());
/* generate worksheet and workbook */
const worksheet = XLSX.utils.aoa_to_sheet([
["Cell", "A1", "RC"],
[
{t:"n", f:"LEN(A1)"}, // A2
{t:"s", f:"GetFormulaA1(A2)"}, // B2
{t:"s", f:"GetFormulaRC(A2)"} // C2
]
]);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
/* generate worksheet and workbook */
const worksheet = XLSX.utils.aoa_to_sheet([
["Cell", "A1", "RC"],
[
{t:"n", f:"LEN(A1)"}, // A2
{t:"s", f:"GetFormulaA1(A2)"}, // B2
{t:"s", f:"GetFormulaRC(A2)"} // C2
]
]);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
/* add VBA blob to new workbook */
workbook.vbaraw = blob;
/* add VBA blob to new workbook */
workbook.vbaraw = blob;
/* create an XLSM file and try to save to SheetJSVBAPreparedNeu.xlsm */
XLSX.writeFile(workbook, "SheetJSVBAPreparedNeu.xlsm");
}}><b>Click to Generate file!</b></button> ); }
/* export data to the specified file format */
XLSX.writeFile(workbook, `SheetJSVBAPreparedNeu.${ext}`);
}
return ["xlsm", "xlsb", "xls"].map((ext) => ( <>
<button onClick={() => exportFile(ext)}>
<b>Click to Generate {ext.toUpperCase()}!</b>
</button>
<br/>
</> ));
}
```
## Details

Binary file not shown.

@ -14,4 +14,4 @@ curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js
curl -LO https://sheetjs.com/pres.xlsx
curl -L -o src/main.rs https://docs.sheetjs.com/boa/main.rs
cargo run --release; echo $?
cargo run --release pres.xlsx; echo $?

@ -9,7 +9,7 @@ cd SheetJSJurassic
dotnet new console
dotnet run
dotnet add package Jurassic --version 3.2.8
dotnet add package Jurassic --version 3.2.9
curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js
curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.mini.min.js

@ -7,7 +7,7 @@ rm -rf sheetjs-mu
mkdir sheetjs-mu
cd sheetjs-mu
curl -LO https://mujs.com/downloads/mujs-1.3.5.zip
curl -LO https://mujs.com/downloads/mujs-1.3.6.zip
unzip mujs-*.zip
rm mujs-*.zip
cd mujs-*

@ -7,7 +7,7 @@ cd sheetjs-quickjs
git clone https://github.com/bellard/quickjs
cd quickjs
git checkout 6e2e68f
git checkout 3306254
make
cd ..