2022-07-26 19:24:43 +00:00
|
|
|
---
|
|
|
|
title: Legacy Frameworks
|
2023-01-10 00:31:37 +00:00
|
|
|
pagination_prev: demos/index
|
2023-02-28 11:40:44 +00:00
|
|
|
pagination_next: demos/grid/index
|
2023-01-09 05:08:30 +00:00
|
|
|
sidebar_position: 9
|
|
|
|
sidebar_custom_props:
|
|
|
|
skip: 1
|
2022-07-26 19:24:43 +00:00
|
|
|
---
|
|
|
|
|
|
|
|
import current from '/version.js';
|
|
|
|
|
|
|
|
Over the years, many frameworks have been released. Some were popular years ago
|
|
|
|
but have waned in recent years. There are still many deployments using these
|
2022-08-19 06:42:18 +00:00
|
|
|
frameworks and it is oftentimes easier to continue maintenance than to rewrite
|
2022-07-26 19:24:43 +00:00
|
|
|
using modern web techniques.
|
|
|
|
|
|
|
|
SheetJS libraries strive to maintain broad browser and JS engine compatibility.
|
|
|
|
|
|
|
|
## Integration
|
|
|
|
|
2022-11-13 20:45:13 +00:00
|
|
|
["Standalone Browser Scripts"](/docs/getting-started/installation/standalone)
|
|
|
|
section has instructions for obtaining or referencing the standalone scripts.
|
|
|
|
These are designed to be referenced with `<script>` tags.
|
2022-07-26 19:24:43 +00:00
|
|
|
|
2022-08-09 04:23:52 +00:00
|
|
|
## Internet Explorer
|
|
|
|
|
|
|
|
:::warning
|
|
|
|
|
|
|
|
Internet Explorer is unmaintained and users should consider modern browsers.
|
|
|
|
The SheetJS testing grid still includes IE and should work.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
The modern upload and download strategies are not available in older versions of
|
2022-11-13 20:45:13 +00:00
|
|
|
IE, but there are approaches using ActiveX or Flash.
|
2022-08-09 04:23:52 +00:00
|
|
|
|
|
|
|
<details><summary><b>Complete Example</b> (click to show)</summary>
|
|
|
|
|
|
|
|
This demo includes all of the support files for the Flash and ActiveX methods.
|
|
|
|
|
|
|
|
1) Download the standalone script and shim to a server that will host the demo:
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js`}>shim.min.js</a></li>
|
2022-09-05 10:00:35 +00:00
|
|
|
<li><a href={`https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
2022-08-09 04:23:52 +00:00
|
|
|
</ul>
|
|
|
|
|
|
|
|
2) [Download the demo ZIP](pathname:///ie/SheetJSIESupport.zip) to the server.
|
|
|
|
|
|
|
|
The ZIP includes the demo HTML file as well as the Downloadify support files.
|
|
|
|
|
|
|
|
Extract the contents to the same folder as the scripts from step 1
|
|
|
|
|
|
|
|
3) Start a HTTP server:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
npx -y http-server .
|
|
|
|
```
|
|
|
|
|
|
|
|
4) Access the `index.html` from a machine with Internet Explorer.
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
|
|
|
<details><summary><b>Other Live Demos</b> (click to show)</summary>
|
|
|
|
|
2022-11-13 20:45:13 +00:00
|
|
|
:::caution
|
2022-08-09 04:23:52 +00:00
|
|
|
|
|
|
|
The hosted solutions may not work in older versions of Windows. For testing,
|
|
|
|
demo pages should be downloaded and hosted using a simple HTTP server.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
2022-10-20 18:47:20 +00:00
|
|
|
<https://oss.sheetjs.com/sheetjs/ajax.html> uses XMLHttpRequest to download test
|
2022-08-25 08:22:28 +00:00
|
|
|
files and convert to CSV
|
2022-08-09 04:23:52 +00:00
|
|
|
|
|
|
|
<https://oss.sheetjs.com/sheetjs/> demonstrates reading files with `FileReader`.
|
|
|
|
|
|
|
|
Older versions of IE do not support HTML5 File API but do support Base64.
|
|
|
|
|
2022-08-23 03:20:02 +00:00
|
|
|
On MacOS you can get the Base64 encoding with:
|
2022-08-09 04:23:52 +00:00
|
|
|
|
|
|
|
```bash
|
|
|
|
$ <target_file base64 | pbcopy
|
|
|
|
```
|
|
|
|
|
|
|
|
On Windows XP and up you can get the Base64 encoding using `certutil`:
|
|
|
|
|
|
|
|
```cmd
|
|
|
|
> certutil -encode target_file target_file.b64
|
|
|
|
```
|
|
|
|
|
|
|
|
(note: You have to open the file and remove the header and footer lines)
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
|
|
|
### Upload Strategies
|
|
|
|
|
|
|
|
IE10 and IE11 support the standard HTML5 FileReader API:
|
|
|
|
|
|
|
|
```js
|
|
|
|
function handle_fr(e) {
|
|
|
|
var f = e.target.files[0];
|
|
|
|
var reader = new FileReader();
|
|
|
|
reader.onload = function(e) {
|
|
|
|
var wb = XLSX.read(e.target.result);
|
|
|
|
process_wb(wb); // DO SOMETHING WITH wb HERE
|
|
|
|
};
|
|
|
|
reader.readAsArrayBuffer(f);
|
|
|
|
}
|
|
|
|
input_dom_element.addEventListener('change', handle_fr, false);
|
|
|
|
```
|
|
|
|
|
|
|
|
`Blob#arrayBuffer` is not supported in IE!
|
|
|
|
|
2022-08-25 08:22:28 +00:00
|
|
|
**ActiveX Upload**
|
2022-08-09 04:23:52 +00:00
|
|
|
|
|
|
|
Through the `Scripting.FileSystemObject` object model, a script in the VBScript
|
2022-08-25 08:22:28 +00:00
|
|
|
scripting language can read from an arbitrary path on the file system. The shim
|
|
|
|
includes a special `IE_LoadFile` function to read binary data from files. This
|
2022-08-09 04:23:52 +00:00
|
|
|
should be called from a file input `onchange` event:
|
|
|
|
|
|
|
|
```js
|
|
|
|
var input_dom_element = document.getElementById("file");
|
|
|
|
function handle_ie() {
|
|
|
|
/* get data from selected file */
|
|
|
|
var path = input_dom_element.value;
|
|
|
|
var bstr = IE_LoadFile(path);
|
|
|
|
/* read workbook */
|
|
|
|
var wb = XLSX.read(bstr, {type: 'binary'});
|
|
|
|
/* DO SOMETHING WITH workbook HERE */
|
|
|
|
}
|
|
|
|
input_dom_element.attachEvent('onchange', handle_ie);
|
|
|
|
```
|
|
|
|
|
|
|
|
### Download Strategies
|
|
|
|
|
|
|
|
As part of the File API implementation, IE10 and IE11 provide the `msSaveBlob`
|
|
|
|
and `msSaveOrOpenBlob` functions to save blobs to the client computer. This
|
|
|
|
approach is embedded in `XLSX.writeFile` and no additional shims are necessary.
|
|
|
|
|
|
|
|
**Flash-based Download**
|
|
|
|
|
2022-08-25 08:22:28 +00:00
|
|
|
It is possible to write to the file system using a SWF file. `Downloadify`
|
2022-08-09 04:23:52 +00:00
|
|
|
implements one solution. Since a genuine click is required, there is no way to
|
|
|
|
force a download. The safest data type is Base64:
|
|
|
|
|
|
|
|
```js
|
|
|
|
// highlight-next-line
|
|
|
|
Downloadify.create(element_id, {
|
|
|
|
/* Downloadify boilerplate */
|
|
|
|
swf: 'downloadify.swf',
|
|
|
|
downloadImage: 'download.png',
|
|
|
|
width: 100, height: 30,
|
|
|
|
transparent: false, append: false,
|
|
|
|
|
|
|
|
// highlight-start
|
|
|
|
/* Key parameters */
|
|
|
|
filename: "test.xlsx",
|
|
|
|
dataType: 'base64',
|
|
|
|
data: function() { return XLSX.write(wb, { bookType: "xlsx", type: 'base64' }); }
|
|
|
|
// highlight-end
|
|
|
|
// highlight-next-line
|
|
|
|
});
|
|
|
|
```
|
|
|
|
|
2022-08-25 08:22:28 +00:00
|
|
|
**ActiveX Download**
|
2022-08-09 04:23:52 +00:00
|
|
|
|
|
|
|
Through the `Scripting.FileSystemObject` object model, a script in the VBScript
|
|
|
|
scripting language can write to an arbitrary path on the filesystem. The shim
|
|
|
|
includes a special `IE_SaveFile` function to write binary strings to file. It
|
|
|
|
attempts to write to the Downloads folder or Documents folder or Desktop.
|
|
|
|
|
|
|
|
This approach can be triggered, but it requires the user to enable ActiveX. It
|
|
|
|
is embedded as a strategy in `writeFile` and used only if the shim script is
|
|
|
|
included in the page and the relevant features are enabled on the target system.
|
|
|
|
|
|
|
|
|
2022-07-26 19:24:43 +00:00
|
|
|
## Frameworks
|
|
|
|
|
2022-08-01 05:34:23 +00:00
|
|
|
### AngularJS
|
|
|
|
|
2022-11-13 20:45:13 +00:00
|
|
|
AngularJS was a front-end MVC framework that was discontinued by Google in 2022.
|
|
|
|
It should not be confused with the modern framework "Angular".
|
2022-08-01 05:34:23 +00:00
|
|
|
|
|
|
|
The [Live demo](pathname:///angularjs/index.html) shows a simple table that is
|
|
|
|
updated with file data and exported to spreadsheets.
|
|
|
|
|
|
|
|
This demo uses AngularJS 1.5.0.
|
|
|
|
|
|
|
|
<details><summary><b>Full Exposition</b> (click to show)</summary>
|
|
|
|
|
|
|
|
**Array of Objects**
|
|
|
|
|
|
|
|
A common data table is often stored as an array of objects:
|
|
|
|
|
|
|
|
```js
|
|
|
|
$scope.data = [
|
|
|
|
{ Name: "Bill Clinton", Index: 42 },
|
|
|
|
{ Name: "GeorgeW Bush", Index: 43 },
|
|
|
|
{ Name: "Barack Obama", Index: 44 },
|
|
|
|
{ Name: "Donald Trump", Index: 45 }
|
|
|
|
];
|
|
|
|
```
|
|
|
|
|
|
|
|
This neatly maps to a table with `ng-repeat`:
|
|
|
|
|
|
|
|
```html
|
|
|
|
<table id="sjs-table">
|
|
|
|
<tr><th>Name</th><th>Index</th></tr>
|
|
|
|
<tr ng-repeat="row in data">
|
|
|
|
<td>{{row.Name}}</td>
|
|
|
|
<td>{{row.Index}}</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
```
|
|
|
|
|
|
|
|
The `$http` service can request binary data using the `"arraybuffer"` response
|
|
|
|
type coupled with `XLSX.read` with type `"array"`:
|
|
|
|
|
|
|
|
```js
|
|
|
|
$http({
|
|
|
|
method:'GET',
|
|
|
|
url:'https://sheetjs.com/pres.xlsx',
|
|
|
|
responseType:'arraybuffer'
|
|
|
|
}).then(function(data) {
|
|
|
|
var wb = XLSX.read(data.data, {type:"array"});
|
|
|
|
var d = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
|
|
|
|
$scope.data = d;
|
|
|
|
}, function(err) { console.log(err); });
|
|
|
|
```
|
|
|
|
|
|
|
|
The HTML table can be directly exported with `XLSX.utils.table_to_book`:
|
|
|
|
|
|
|
|
```js
|
|
|
|
var wb = XLSX.utils.table_to_book(document.getElementById('sjs-table'));
|
|
|
|
XLSX.writeFile(wb, "export.xlsx");
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Import Directive**
|
|
|
|
|
|
|
|
A general import directive is fairly straightforward:
|
|
|
|
|
|
|
|
- Define the `importSheetJs` directive in the app:
|
|
|
|
|
|
|
|
```js
|
|
|
|
app.directive("importSheetJs", [SheetJSImportDirective]);
|
|
|
|
```
|
|
|
|
|
|
|
|
- Add the attribute `import-sheet-js=""` to the file input element:
|
|
|
|
|
|
|
|
```html
|
|
|
|
<input type="file" import-sheet-js="" multiple="false" />
|
|
|
|
```
|
|
|
|
|
|
|
|
- Define the directive:
|
|
|
|
|
|
|
|
```js
|
|
|
|
function SheetJSImportDirective() {
|
|
|
|
return {
|
|
|
|
scope: { opts: '=' },
|
|
|
|
link: function ($scope, $elm) {
|
|
|
|
$elm.on('change', function (changeEvent) {
|
|
|
|
var reader = new FileReader();
|
|
|
|
|
|
|
|
reader.onload = function (e) {
|
|
|
|
/* read workbook */
|
|
|
|
var ab = e.target.result;
|
|
|
|
var workbook = XLSX.read(ab);
|
|
|
|
|
|
|
|
/* DO SOMETHING WITH workbook HERE */
|
|
|
|
};
|
|
|
|
|
|
|
|
reader.readAsArrayBuffer(changeEvent.target.files[0]);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Export Service**
|
|
|
|
|
|
|
|
An export can be triggered at any point! Depending on how data is represented,
|
|
|
|
a workbook object can be built using the utility functions. For example, using
|
|
|
|
an array of objects:
|
|
|
|
|
|
|
|
```js
|
|
|
|
/* starting from this data */
|
|
|
|
var data = [
|
|
|
|
{ name: "Barack Obama", pres: 44 },
|
|
|
|
{ name: "Donald Trump", pres: 45 }
|
|
|
|
];
|
|
|
|
|
|
|
|
/* generate a worksheet */
|
|
|
|
var ws = XLSX.utils.json_to_sheet(data);
|
|
|
|
|
|
|
|
/* add to workbook */
|
|
|
|
var wb = XLSX.utils.book_new();
|
|
|
|
XLSX.utils.book_append_sheet(wb, ws, "Presidents");
|
|
|
|
|
|
|
|
/* write workbook and force a download */
|
|
|
|
XLSX.writeFile(wb, "sheetjs.xlsx");
|
|
|
|
```
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
2022-08-30 22:12:52 +00:00
|
|
|
### Dojo Toolkit
|
|
|
|
|
|
|
|
_Live Demos_
|
|
|
|
|
|
|
|
- [Download and display data](pathname:///dojo/read.html)
|
|
|
|
- [Fetch JSON and generate a workbook](pathname:///dojo/write.html)
|
|
|
|
|
|
|
|
|
2022-10-30 05:45:37 +00:00
|
|
|
The ["AMD" instructions](/docs/getting-started/installation/amd#dojo-toolkit)
|
2022-08-30 22:12:52 +00:00
|
|
|
includes details for use with `require`.
|
|
|
|
|
|
|
|
<details><summary><b>Integration in the demos</b> (click to show)</summary>
|
|
|
|
|
|
|
|
The demos use the async loading strategy with the SheetJS CDN:
|
|
|
|
|
|
|
|
```html
|
|
|
|
<script>
|
|
|
|
dojoConfig = {
|
|
|
|
packages: [
|
|
|
|
{ name: "xlsx", location: "https://cdn.sheetjs.com/xlsx-latest/package/dist", main: "xlsx.full.min" }
|
|
|
|
]
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js" data-dojo-config="isDebug:1, async:1"></script>
|
|
|
|
<script>
|
|
|
|
require(["dojo/request/xhr", "xlsx"], function(xhr, _XLSX) {
|
|
|
|
/* XLSX-related operations happen in the callback */
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
```
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
2022-10-30 05:45:37 +00:00
|
|
|
The ["Dojo" section in "Bundlers"](/docs/demos/bundler#dojo) includes a complete example
|
|
|
|
mirroring the [official example](/docs/getting-started/example)
|
2022-08-30 22:12:52 +00:00
|
|
|
|
|
|
|
<details><summary><b>Details</b> (click to show)</summary>
|
|
|
|
|
|
|
|
_Reading Data_
|
|
|
|
|
|
|
|
When fetching spreadsheets with XHR, `handleAs: "arraybuffer"` yields an
|
|
|
|
`ArrayBuffer` which can be passed to `XLSX.read`:
|
|
|
|
|
|
|
|
```html
|
|
|
|
<div id="tbl"></div>
|
|
|
|
<script>
|
|
|
|
require(["dojo/request/xhr", "xlsx"], function(xhr, _XLSX) {
|
|
|
|
xhr("https://sheetjs.com/pres.numbers", {
|
|
|
|
headers: { "X-Requested-With": null },
|
|
|
|
// highlight-next-line
|
|
|
|
handleAs: "arraybuffer"
|
|
|
|
}).then(function(ab) {
|
|
|
|
/* read ArrayBuffer */
|
|
|
|
// highlight-next-line
|
|
|
|
var wb = XLSX.read(ab);
|
|
|
|
/* display first worksheet data */
|
|
|
|
var ws = wb.Sheets[wb.SheetNames[0]];
|
|
|
|
document.getElementById("tbl").innerHTML = XLSX.utils.sheet_to_html(ws);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
```
|
|
|
|
|
|
|
|
:::note
|
|
|
|
|
|
|
|
The `X-Requested-With` header setting resolves some issues related to CORS.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
_Writing Data_
|
|
|
|
|
|
|
|
`XLSX.writeFile` works as expected:
|
|
|
|
|
|
|
|
```html
|
|
|
|
<script>
|
|
|
|
require(["xlsx"], function(_XLSX) {
|
|
|
|
var ws = XLSX.utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]);
|
|
|
|
var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
|
|
|
|
/* create an XLSX file and try to save to SheetJSDojo.xlsx */
|
|
|
|
// highlight-next-line
|
|
|
|
XLSX.writeFile(workbook, "SheetJSDojo.xlsx");
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
```
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
|
|
|
|
2022-07-26 19:24:43 +00:00
|
|
|
### KnockoutJS
|
|
|
|
|
2022-11-13 20:45:13 +00:00
|
|
|
KnockoutJS was a popular MVVM framework.
|
2022-07-26 19:24:43 +00:00
|
|
|
|
|
|
|
The [Live demo](pathname:///knockout/knockout.html) shows a view model that is
|
|
|
|
updated with file data and exported to spreadsheets.
|
|
|
|
|
2022-08-01 05:34:23 +00:00
|
|
|
<details><summary><b>Full Exposition</b> (click to show)</summary>
|
2022-07-26 19:24:43 +00:00
|
|
|
|
2022-08-01 05:34:23 +00:00
|
|
|
**State**
|
2022-07-26 19:24:43 +00:00
|
|
|
|
|
|
|
Arrays of arrays are the simplest data structure for representing worksheets.
|
|
|
|
|
|
|
|
```js
|
|
|
|
var aoa = [
|
|
|
|
[1, 2], // A1 = 1, B1 = 2
|
|
|
|
[3, 4] // A1 = 3, B1 = 4
|
|
|
|
];
|
|
|
|
```
|
|
|
|
|
|
|
|
`ko.observableArray` should be used to create the view model:
|
|
|
|
|
|
|
|
```js
|
|
|
|
function ViewModel() {
|
|
|
|
/* use an array of arrays */
|
|
|
|
this.aoa = ko.observableArray([ [1,2], [3,4] ]);
|
|
|
|
}
|
|
|
|
/* create model */
|
|
|
|
var model = new ViewModel();
|
|
|
|
ko.applyBindings(model);
|
|
|
|
```
|
|
|
|
|
|
|
|
`XLSX.utils.sheet_to_json` with `header: 1` generates data for the model:
|
|
|
|
|
|
|
|
```js
|
|
|
|
/* starting from a `wb` workbook object, pull first worksheet */
|
|
|
|
var ws = wb.Sheets[wb.SheetNames[0]];
|
|
|
|
/* convert the worksheet to an array of arrays */
|
|
|
|
var aoa = XLSX.utils.sheet_to_json(ws, {header:1});
|
|
|
|
/* update model */
|
|
|
|
model.aoa(aoa);
|
|
|
|
```
|
|
|
|
|
|
|
|
`XLSX.utils.aoa_to_sheet` generates worksheets from the model:
|
|
|
|
|
|
|
|
```js
|
|
|
|
var aoa = model.aoa();
|
|
|
|
var ws = XLSX.utils.aoa_to_sheet(aoa);
|
|
|
|
```
|
|
|
|
|
2022-08-01 05:34:23 +00:00
|
|
|
**Data Binding**
|
2022-07-26 19:24:43 +00:00
|
|
|
|
|
|
|
`data-bind="foreach: ..."` provides a simple approach for binding to `TABLE`:
|
|
|
|
|
|
|
|
```html
|
|
|
|
<table data-bind="foreach: aoa">
|
|
|
|
<tr data-bind="foreach: $data">
|
|
|
|
<td><span data-bind="text: $data"></span></td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
```
|
|
|
|
|
|
|
|
Unfortunately the nested `"foreach: $data"` binding is read-only. A two-way
|
|
|
|
binding is possible using the `$parent` and `$index` binding context properties:
|
|
|
|
|
|
|
|
```html
|
|
|
|
<table data-bind="foreach: aoa">
|
|
|
|
<tr data-bind="foreach: $data">
|
|
|
|
<td><input data-bind="value: $parent[$index()]" /></td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
```
|
2022-08-01 05:34:23 +00:00
|
|
|
|
|
|
|
</details>
|