---
title: AngularJS
pagination_prev: demos/index
pagination_next: demos/grid/index
sidebar_position: 7
---

import current from '/version.js';
import CodeBlock from '@theme/CodeBlock';

:::warning pass

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.

:::

[AngularJS](https://angularjs.org/) is a JS library for building user interfaces.

## Demo

:::note

This demo was last run on 2023 August 27 using AngularJS `1.8.2`

:::

[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 [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
can be referenced in a `SCRIPT` tag from the HTML entry point 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`:

<CodeBlock language="html" title="index.html">{`\
<!DOCTYPE html>
<html ng-app="s5s">
<head>
  <title>SheetJS + AngularJS</title>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
  <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>
</head>
<body>
<h3><a href="https://sheetjs.com">SheetJS + AngularJS demo</a></h3>
\n\
<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>
\n\
<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>
</html>`}
</CodeBlock>

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`:

<CodeBlock language="html" title="index.html">{`\
<!DOCTYPE html>
<html ng-app="s5s">
<head>
  <title>SheetJS + AngularJS</title>
  <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>
  <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>
</head>
<body>
<h3><a href="https://sheetjs.com">SheetJS + AngularJS demo</a></h3>
\n\
<div ng-controller="sheetjs">
  <button ng-click="exportSheetJS()">Export Table</button>
  <div ng-bind-html="data" id="tbl"></div>
</div>
\n\
<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>
</html>`}
</CodeBlock>

2) Start a local web server with `npx http-server .` and access the displayed
URL with a web browser (typically `http://localhost:8080`)

</details>