2023-04-09 00:20:50 +00:00
|
|
|
---
|
|
|
|
title: AngularJS
|
|
|
|
pagination_prev: demos/index
|
|
|
|
pagination_next: demos/grid/index
|
|
|
|
sidebar_position: 7
|
|
|
|
---
|
|
|
|
|
2023-05-03 03:40:40 +00:00
|
|
|
import current from '/version.js';
|
|
|
|
import CodeBlock from '@theme/CodeBlock';
|
|
|
|
|
2023-08-28 22:40:53 +00:00
|
|
|
:::warning pass
|
2023-04-09 00:20:50 +00:00
|
|
|
|
|
|
|
This demo is for the legacy AngularJS framework (version 1).
|
|
|
|
|
|
|
|
"Angular" now commonly refers to the new framework starting with version 2.
|
|
|
|
[The "Angular" demo](/docs/demos/frontend/angular) covers the new framework.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
2023-08-18 20:39:12 +00:00
|
|
|
[AngularJS](https://angularjs.org/) is a JS library for building user interfaces.
|
2023-04-09 00:20:50 +00:00
|
|
|
|
|
|
|
## Demo
|
|
|
|
|
|
|
|
:::note
|
|
|
|
|
2023-08-28 22:40:53 +00:00
|
|
|
This demo was last run on 2023 August 27 using AngularJS `1.8.2`
|
2023-04-09 00:20:50 +00:00
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
[Click here for a live standalone integration demo.](pathname:///angularjs/)
|
|
|
|
|
|
|
|
The demo uses an array of objects as its internal state. It fetches and displays
|
|
|
|
data on load. It also includes a button for exporting data to file and a file
|
|
|
|
input element for loading user-submitted files.
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
|
|
|
The [Standalone scripts](/docs/getting-started/installation/standalone) can be
|
|
|
|
referenced in a `SCRIPT` tag from the HTML entrypoint page.
|
|
|
|
|
|
|
|
The `$http` service can request binary data using `"arraybuffer"` response type.
|
|
|
|
This maps to the `"array"` input format for `XLSX.read`:
|
|
|
|
|
|
|
|
```js
|
|
|
|
app.controller('sheetjs', function($scope, $http) {
|
|
|
|
$http({
|
|
|
|
method:'GET', url:'https://sheetjs.com/pres.xlsx',
|
|
|
|
// highlight-next-line
|
|
|
|
responseType:'arraybuffer'
|
|
|
|
}).then(function(data) {
|
|
|
|
// highlight-next-line
|
|
|
|
var wb = XLSX.read(data.data, {type:"array"});
|
|
|
|
/* DO SOMETHING WITH wb HERE */
|
|
|
|
$scope.data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
|
|
|
|
}, function(err) { console.log(err); });
|
|
|
|
});
|
|
|
|
```
|
|
|
|
|
|
|
|
<details><summary><b>Parsing User-Submitted Files</b> (click to show)</summary>
|
|
|
|
|
|
|
|
For file input elements, a general import directive is fairly straightforward:
|
|
|
|
|
|
|
|
1) Add an `INPUT` element with attribute `import-sheet-js=""`:
|
|
|
|
|
|
|
|
```html
|
|
|
|
<input type="file" import-sheet-js="" multiple="false" />
|
|
|
|
```
|
|
|
|
|
|
|
|
2) Define the `SheetJSImportDirective` directive function:
|
|
|
|
|
|
|
|
```js
|
|
|
|
function SheetJSImportDirective() { return {
|
|
|
|
scope: false,
|
|
|
|
link: function ($scope, $elm) {
|
|
|
|
$elm.on('change', function (changeEvent) {
|
|
|
|
var reader = new FileReader();
|
|
|
|
reader.onload = function (e) {
|
|
|
|
var wb = XLSX.read(e.target.result);
|
|
|
|
|
|
|
|
/* DO SOMETHING WITH wb HERE */
|
|
|
|
$scope.apply(function() {
|
|
|
|
$scope.data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
reader.readAsArrayBuffer(changeEvent.target.files[0]);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}; }
|
|
|
|
```
|
|
|
|
|
|
|
|
3) Define the `importSheetJs` directive in the app:
|
|
|
|
|
|
|
|
```js
|
|
|
|
app.directive("importSheetJs", [SheetJSImportDirective]);
|
|
|
|
```
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
|
|
|
## Internal State
|
|
|
|
|
|
|
|
The various SheetJS APIs work with various data shapes. The preferred state
|
|
|
|
depends on the application.
|
|
|
|
|
|
|
|
### Array of Objects
|
|
|
|
|
|
|
|
Typically, some users will create a spreadsheet with source data that should be
|
|
|
|
loaded into the site. This sheet will have known columns. For example, our
|
|
|
|
[presidents sheet](https://sheetjs.com/pres.xlsx) has "Name" / "Index" columns:
|
|
|
|
|
|
|
|
![`pres.xlsx` data](pathname:///pres.png)
|
|
|
|
|
|
|
|
This naturally maps to an array of typed objects, as in the example below:
|
|
|
|
|
|
|
|
```js
|
|
|
|
app.controller('sheetjs', function($scope, $http) {
|
|
|
|
$http({ method:'GET', url:'https://sheetjs.com/pres.xlsx', responseType:'arraybuffer' }).then(function(data) {
|
|
|
|
var wb = XLSX.read(data.data, {type:"array"});
|
|
|
|
// highlight-next-line
|
|
|
|
$scope.data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
|
|
|
|
}, function(err) { console.log(err); });
|
|
|
|
});
|
|
|
|
```
|
|
|
|
|
|
|
|
`data` will be an array of objects:
|
|
|
|
|
|
|
|
```js
|
|
|
|
[
|
|
|
|
{ Name: "Bill Clinton", Index: 42 },
|
|
|
|
{ Name: "GeorgeW Bush", Index: 43 },
|
|
|
|
{ Name: "Barack Obama", Index: 44 },
|
|
|
|
{ Name: "Donald Trump", Index: 45 },
|
|
|
|
{ Name: "Joseph Biden", Index: 46 }
|
|
|
|
]
|
|
|
|
```
|
|
|
|
|
|
|
|
A component will typically loop over the data using `ng-repeat`. The following
|
|
|
|
template generates a TABLE with a row for each President:
|
|
|
|
|
|
|
|
```html
|
|
|
|
<table id="sjs-table">
|
|
|
|
<tr><th>Name</th><th>Index</th></tr>
|
|
|
|
<tr ng-repeat="row in data track by $index">
|
|
|
|
<td>{{row.Name}}</td>
|
|
|
|
<td>{{row.Index}}</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
```
|
|
|
|
|
|
|
|
`XLSX.utils.json_to_sheet` can generate a worksheet from the data:
|
|
|
|
|
|
|
|
```js
|
|
|
|
/* assuming $scope.data is an array of objects */
|
|
|
|
$scope.exportSheetJS = function() {
|
|
|
|
/* generate a worksheet */
|
|
|
|
var ws = XLSX.utils.json_to_sheet($scope.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, "SheetJSAngularJSAoO.xlsx");
|
|
|
|
};
|
|
|
|
```
|
|
|
|
|
|
|
|
<details><summary><b>Complete Example</b> (click to show)</summary>
|
|
|
|
|
|
|
|
1) Save the following to `index.html`:
|
|
|
|
|
2023-05-03 03:40:40 +00:00
|
|
|
<CodeBlock language="html" title="index.html">{`\
|
2023-04-09 00:20:50 +00:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html ng-app="s5s">
|
|
|
|
<head>
|
|
|
|
<title>SheetJS + AngularJS</title>
|
2023-08-28 22:40:53 +00:00
|
|
|
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
|
2023-05-03 03:40:40 +00:00
|
|
|
<script src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js"></script>
|
|
|
|
<script src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>
|
2023-04-09 00:20:50 +00:00
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h3><a href="https://sheetjs.com">SheetJS + AngularJS demo</a></h3>
|
2023-05-03 03:40:40 +00:00
|
|
|
\n\
|
2023-04-09 00:20:50 +00:00
|
|
|
<div ng-controller="sheetjs">
|
|
|
|
<button ng-click="exportSheetJS()">Export Table</button>
|
|
|
|
<table id="s5s-table">
|
|
|
|
<tr><th>Name</th><th>Index</th></tr>
|
|
|
|
<tr ng-repeat="row in data track by $index">
|
|
|
|
<td>{{row.Name}}</td>
|
|
|
|
<td>{{row.Index}}</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
</div>
|
2023-05-03 03:40:40 +00:00
|
|
|
\n\
|
2023-04-09 00:20:50 +00:00
|
|
|
<script>
|
|
|
|
var app = angular.module('s5s', []);
|
|
|
|
app.controller('sheetjs', function($scope, $http) {
|
|
|
|
$scope.exportSheetJS = function() {
|
|
|
|
var ws = XLSX.utils.json_to_sheet($scope.data);
|
|
|
|
var wb = XLSX.utils.book_new();
|
|
|
|
XLSX.utils.book_append_sheet(wb, ws, "Presidents");
|
|
|
|
XLSX.writeFile(wb, "SheetJSAngularJSAoO.xlsx");
|
|
|
|
};
|
|
|
|
$http({
|
|
|
|
method:'GET',
|
|
|
|
url:'https://sheetjs.com/pres.xlsx',
|
|
|
|
responseType:'arraybuffer'
|
|
|
|
}).then(function(data) {
|
|
|
|
var wb = XLSX.read(data.data, {type:"array"});
|
|
|
|
var data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
|
|
|
|
$scope.data = data;
|
|
|
|
}, function(err) { console.log(err); });
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
</body>
|
2023-05-03 03:40:40 +00:00
|
|
|
</html>`}
|
|
|
|
</CodeBlock>
|
2023-04-09 00:20:50 +00:00
|
|
|
|
|
|
|
2) Start a local web server with `npx http-server .` and access the displayed
|
|
|
|
URL with a web browser (typically `http://localhost:8080`)
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
|
|
|
### HTML
|
|
|
|
|
|
|
|
The main disadvantage of the Array of Objects approach is the specific nature
|
|
|
|
of the columns. For more general use, passing around an Array of Arrays works.
|
|
|
|
However, this does not handle merge cells well!
|
|
|
|
|
|
|
|
The `sheet_to_html` function generates HTML that is aware of merges and other
|
|
|
|
worksheet features. The generated HTML does not contain any `<script>` tags,
|
|
|
|
and should therefore be safe to pass to an `ng-bind-html` binding. This approach
|
|
|
|
requires the `ngSanitize` plugin.
|
|
|
|
|
|
|
|
```html
|
|
|
|
<div ng-controller="sheetjs">
|
|
|
|
<!-- highlight-next-line -->
|
|
|
|
<div ng-bind-html="data" id="tbl"></div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
// highlight-next-line
|
|
|
|
var app = angular.module('s5s', ['ngSanitize']);
|
|
|
|
app.controller('sheetjs', function($scope, $http) {
|
|
|
|
$http({ method:'GET', url:'https://sheetjs.com/pres.xlsx', responseType:'arraybuffer' }).then(function(data) {
|
|
|
|
var wb = XLSX.read(data.data, {type:"array"});
|
|
|
|
// highlight-next-line
|
|
|
|
$scope.data = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
|
|
|
|
}, function(err) { console.log(err); });
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
```
|
|
|
|
|
|
|
|
The HTML table can be directly exported with `XLSX.utils.table_to_book`:
|
|
|
|
|
|
|
|
```js
|
|
|
|
$scope.exportSheetJS = function() {
|
|
|
|
/* export table element */
|
|
|
|
// highlight-start
|
|
|
|
var tbl = document.getElementById("tbl").getElementsByTagName("TABLE")[0];
|
|
|
|
var wb = XLSX.utils.table_to_book(tbl);
|
|
|
|
// highlight-end
|
|
|
|
XLSX.writeFile(wb, "SheetJSAngularJSHTML.xlsx");
|
|
|
|
};
|
|
|
|
```
|
|
|
|
|
|
|
|
<details><summary><b>Complete Example</b> (click to show)</summary>
|
|
|
|
|
|
|
|
1) Save the following to `index.html`:
|
|
|
|
|
2023-05-03 03:40:40 +00:00
|
|
|
<CodeBlock language="html" title="index.html">{`\
|
2023-04-09 00:20:50 +00:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html ng-app="s5s">
|
|
|
|
<head>
|
|
|
|
<title>SheetJS + AngularJS</title>
|
2023-08-28 22:40:53 +00:00
|
|
|
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
|
|
|
|
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular-sanitize.js"></script>
|
2023-05-03 03:40:40 +00:00
|
|
|
<script src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js"></script>
|
|
|
|
<script src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>
|
2023-04-09 00:20:50 +00:00
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h3><a href="https://sheetjs.com">SheetJS + AngularJS demo</a></h3>
|
2023-05-03 03:40:40 +00:00
|
|
|
\n\
|
2023-04-09 00:20:50 +00:00
|
|
|
<div ng-controller="sheetjs">
|
|
|
|
<button ng-click="exportSheetJS()">Export Table</button>
|
|
|
|
<div ng-bind-html="data" id="tbl"></div>
|
|
|
|
</div>
|
2023-05-03 03:40:40 +00:00
|
|
|
\n\
|
2023-04-09 00:20:50 +00:00
|
|
|
<script>
|
|
|
|
var app = angular.module('s5s', ['ngSanitize']);
|
|
|
|
app.controller('sheetjs', function($scope, $http) {
|
|
|
|
$scope.exportSheetJS = function() {
|
|
|
|
var tbl = document.getElementById("tbl").getElementsByTagName("TABLE")[0];
|
|
|
|
var wb = XLSX.utils.table_to_book(tbl);
|
|
|
|
XLSX.writeFile(wb, "SheetJSAngularJSHTML.xlsx");
|
|
|
|
};
|
|
|
|
$http({
|
|
|
|
method:'GET',
|
|
|
|
url:'https://sheetjs.com/pres.xlsx',
|
|
|
|
responseType:'arraybuffer'
|
|
|
|
}).then(function(data) {
|
|
|
|
var wb = XLSX.read(data.data, {type:"array"});
|
|
|
|
$scope.data = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
|
|
|
|
}, function(err) { console.log(err); });
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
</body>
|
2023-05-03 03:40:40 +00:00
|
|
|
</html>`}
|
|
|
|
</CodeBlock>
|
2023-04-09 00:20:50 +00:00
|
|
|
|
|
|
|
2) Start a local web server with `npx http-server .` and access the displayed
|
|
|
|
URL with a web browser (typically `http://localhost:8080`)
|
|
|
|
|
|
|
|
</details>
|