2023-01-05 23:33:49 +00:00
|
|
|
---
|
|
|
|
title: NativeScript
|
2023-02-28 11:40:44 +00:00
|
|
|
pagination_prev: demos/static/index
|
2023-01-05 23:33:49 +00:00
|
|
|
pagination_next: demos/desktop/index
|
|
|
|
sidebar_position: 2
|
|
|
|
sidebar_custom_props:
|
|
|
|
summary: JS + Native Elements
|
|
|
|
---
|
|
|
|
|
2023-04-27 09:12:19 +00:00
|
|
|
import current from '/version.js';
|
2023-05-07 13:58:36 +00:00
|
|
|
import CodeBlock from '@theme/CodeBlock';
|
2023-04-27 09:12:19 +00:00
|
|
|
|
2023-01-05 23:33:49 +00:00
|
|
|
The [NodeJS Module](/docs/getting-started/installation/nodejs) can be imported
|
|
|
|
from the main entrypoint or any script in the project.
|
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
The "Complete Example" creates an app that looks like the screenshots below:
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
<table><thead><tr>
|
|
|
|
<th><a href="#demo">iOS</a></th>
|
|
|
|
</tr></thead><tbody><tr><td>
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
![iOS screenshot](pathname:///mobile/nsios.png)
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
</td></tr></tbody></table>
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
## Integration Details
|
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
The discussion covers the NativeScript + Angular integration. Familiarity with
|
|
|
|
Angular and TypeScript is assumed.
|
|
|
|
|
2023-01-05 23:33:49 +00:00
|
|
|
The `@nativescript/core/file-system` package provides classes for file access.
|
2023-04-03 09:09:59 +00:00
|
|
|
The `File` class does not support binary data, but the file access singleton
|
|
|
|
from `@nativescript/core` does support reading and writing `ArrayBuffer`.
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
Reading and writing data require a URL. The following snippet searches typical
|
|
|
|
document folders for a specified filename:
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
```ts
|
2023-04-03 09:09:59 +00:00
|
|
|
import { Folder, knownFolders, path } from '@nativescript/core/file-system';
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
function get_url_for_filename(filename: string): string {
|
2023-01-05 23:33:49 +00:00
|
|
|
const target: Folder = knownFolders.documents() || knownFolders.ios.sharedPublic();
|
2023-04-03 09:09:59 +00:00
|
|
|
return path.normalize(target.path + "///" + filename);
|
2023-01-05 23:33:49 +00:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
#### Reading data
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
`getFileAccess().readBufferAsync` can read data:
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
```ts
|
2023-04-03 09:09:59 +00:00
|
|
|
import { getFileAccess } from '@nativescript/core';
|
|
|
|
|
|
|
|
/* find appropriate path */
|
|
|
|
const url = get_url_for_filename("SheetJSNS.xls");
|
|
|
|
|
|
|
|
/* get data */
|
|
|
|
const ab: ArrayBuffer = await getFileAccess().readBufferAsync(url);
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
/* read workbook */
|
2023-04-03 09:09:59 +00:00
|
|
|
const wb = read(ab);
|
2023-01-05 23:33:49 +00:00
|
|
|
```
|
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
#### Writing data
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
`getFileAccess().writeBufferAsync` can write data:
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
```ts
|
2023-04-03 09:09:59 +00:00
|
|
|
import { getFileAccess } from '@nativescript/core';
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
/* find appropriate path */
|
|
|
|
const url = get_url_for_filename("SheetJSNS.xls");
|
|
|
|
|
|
|
|
/* generate Uint8Array */
|
|
|
|
const u8: Uint8Array = write(wb, { bookType: 'xls', type: 'binary' });
|
|
|
|
|
|
|
|
/* attempt to save Uint8Array to file */
|
|
|
|
await getFileAccess().writeBufferAsync(url, u8);
|
2023-01-05 23:33:49 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
## Demo
|
|
|
|
|
|
|
|
:::note
|
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
This demo was tested on an Intel Mac on 2023 April 03. NativeScript version
|
|
|
|
(as verified with `ns --version`) is `8.5.1`.
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
The iOS simulator runs iOS 16.2 on an iPhone 14 Pro Max.
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
:::
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
0) Follow the official Environment Setup instructions
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
1) Create a skeleton NativeScript + Angular app:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
ns create SheetJSNS --ng
|
|
|
|
```
|
|
|
|
|
|
|
|
2) Launch the app in the iOS simulator to verify that the demo built properly:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
cd SheetJSNS
|
|
|
|
ns run ios
|
|
|
|
```
|
|
|
|
|
|
|
|
(this may take a while)
|
|
|
|
|
|
|
|
Once the simulator launches and the test app is displayed, end the script by
|
|
|
|
selecting the terminal and entering the key sequence `CTRL + C`
|
|
|
|
|
|
|
|
3) From the project folder, install the library:
|
|
|
|
|
2023-05-07 13:58:36 +00:00
|
|
|
<CodeBlock language="bash">{`\
|
2023-04-27 09:12:19 +00:00
|
|
|
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
2023-05-07 13:58:36 +00:00
|
|
|
</CodeBlock>
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
4) To confirm the library was loaded, change the title to show the version. The
|
|
|
|
differences are highlighted.
|
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
`src/app/item/items.component.ts` should import the version string:
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
```ts title="src/app/item/items.component.ts"
|
|
|
|
// highlight-next-line
|
|
|
|
import { version } from 'xlsx';
|
|
|
|
import { Component, OnInit } from '@angular/core'
|
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
// ...
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
export class ItemsComponent implements OnInit {
|
|
|
|
items: Array<Item>
|
|
|
|
// highlight-next-line
|
|
|
|
version = `SheetJS - ${version}`;
|
|
|
|
|
|
|
|
constructor(private itemService: ItemService) {}
|
2023-04-03 09:09:59 +00:00
|
|
|
// ...
|
2023-01-05 23:33:49 +00:00
|
|
|
```
|
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
`src/app/item/items.component.html` should use the version in the title:
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
```xml title="src/app/item/items.component.html"
|
|
|
|
<!-- highlight-next-line -->
|
|
|
|
<ActionBar [title]="version"></ActionBar>
|
|
|
|
|
|
|
|
<GridLayout>
|
2023-04-03 09:09:59 +00:00
|
|
|
<!-- ... -->
|
2023-01-05 23:33:49 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
Relaunch the app with `ns run ios` and the title bar should show the version.
|
|
|
|
|
|
|
|
![NativeScript Step 4](pathname:///mobile/nativescript4.png)
|
|
|
|
|
|
|
|
5) Add the Import and Export buttons to the template:
|
|
|
|
|
|
|
|
```xml title="src/app/item/items.component.html"
|
|
|
|
<ActionBar [title]="version"></ActionBar>
|
|
|
|
|
|
|
|
<!-- highlight-start -->
|
|
|
|
<StackLayout>
|
|
|
|
<StackLayout orientation="horizontal">
|
|
|
|
<Button text="Import File" (tap)="import()" style="padding: 10px"></Button>
|
|
|
|
<Button text="Export File" (tap)="export()" style="padding: 10px"></Button>
|
|
|
|
</StackLayout>
|
|
|
|
<!-- highlight-end -->
|
|
|
|
<ListView [items]="items">
|
2023-04-03 09:09:59 +00:00
|
|
|
<!-- ... -->
|
2023-01-05 23:33:49 +00:00
|
|
|
</ListView>
|
|
|
|
<!-- highlight-next-line -->
|
|
|
|
</StackLayout>
|
|
|
|
```
|
|
|
|
|
|
|
|
```ts title="src/app/item/items.component.ts"
|
|
|
|
// highlight-start
|
|
|
|
import { version, utils, read, write } from 'xlsx';
|
2023-04-03 09:09:59 +00:00
|
|
|
import { Dialogs, getFileAccess } from '@nativescript/core';
|
|
|
|
import { Folder, knownFolders, path } from '@nativescript/core/file-system';
|
2023-01-05 23:33:49 +00:00
|
|
|
// highlight-end
|
|
|
|
import { Component, OnInit } from '@angular/core'
|
|
|
|
|
|
|
|
import { Item } from './item'
|
|
|
|
import { ItemService } from './item.service'
|
|
|
|
|
|
|
|
// highlight-start
|
2023-04-03 09:09:59 +00:00
|
|
|
function get_url_for_filename(filename: string): string {
|
2023-01-05 23:33:49 +00:00
|
|
|
const target: Folder = knownFolders.documents() || knownFolders.ios.sharedPublic();
|
2023-04-03 09:09:59 +00:00
|
|
|
return path.normalize(target.path + "///" + filename);
|
2023-01-05 23:33:49 +00:00
|
|
|
}
|
|
|
|
// highlight-end
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'ns-items',
|
|
|
|
templateUrl: './items.component.html',
|
|
|
|
})
|
|
|
|
export class ItemsComponent implements OnInit {
|
|
|
|
items: Array<Item>
|
|
|
|
version: string = `SheetJS - ${version}`;
|
|
|
|
|
|
|
|
constructor(private itemService: ItemService) {}
|
|
|
|
|
|
|
|
ngOnInit(): void {
|
|
|
|
this.items = this.itemService.getItems()
|
|
|
|
}
|
|
|
|
|
|
|
|
// highlight-start
|
|
|
|
/* Import button */
|
|
|
|
async import() {
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Export button */
|
|
|
|
async export() {
|
|
|
|
}
|
|
|
|
// highlight-end
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Restart the app process and two buttons should show up at the top:
|
|
|
|
|
|
|
|
![NativeScript Step 5](pathname:///mobile/nativescript5.png)
|
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
6) Implement import and export by adding the highlighted lines:
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
```ts title="src/app/item/items.component.ts"
|
|
|
|
/* Import button */
|
|
|
|
async import() {
|
|
|
|
// highlight-start
|
|
|
|
/* find appropriate path */
|
2023-04-03 09:09:59 +00:00
|
|
|
const url = get_url_for_filename("SheetJSNS.xls");
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
try {
|
2023-04-03 09:09:59 +00:00
|
|
|
await Dialogs.alert(`Attempting to read from SheetJSNS.xls at ${url}`);
|
|
|
|
/* get data */
|
|
|
|
const ab: ArrayBuffer = await getFileAccess().readBufferAsync(url);
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
/* read workbook */
|
2023-04-03 09:09:59 +00:00
|
|
|
const wb = read(ab);
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
/* grab first sheet */
|
|
|
|
const wsname: string = wb.SheetNames[0];
|
|
|
|
const ws = wb.Sheets[wsname];
|
|
|
|
|
|
|
|
/* update table */
|
|
|
|
this.items = utils.sheet_to_json<Item>(ws);
|
2023-04-03 09:09:59 +00:00
|
|
|
} catch(e) { await Dialogs.alert(e.message); }
|
2023-01-05 23:33:49 +00:00
|
|
|
// highlight-end
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Export button */
|
|
|
|
async export() {
|
|
|
|
// highlight-start
|
|
|
|
/* find appropriate path */
|
2023-04-03 09:09:59 +00:00
|
|
|
const url = get_url_for_filename("SheetJSNS.xls");
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
/* create worksheet from data */
|
|
|
|
const ws = utils.json_to_sheet(this.items);
|
|
|
|
|
|
|
|
/* create workbook from worksheet */
|
|
|
|
const wb = utils.book_new();
|
|
|
|
utils.book_append_sheet(wb, ws, "Sheet1");
|
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
/* generate Uint8Array */
|
|
|
|
const u8: Uint8Array = write(wb, { bookType: 'xls', type: 'buffer' });
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
/* attempt to save Uint8Array to file */
|
|
|
|
await getFileAccess().writeBufferAsync(url, u8);
|
|
|
|
await Dialogs.alert(`Wrote to SheetJSNS.xls at ${url}`);
|
|
|
|
} catch(e) { await Dialogs.alert(e.message); }
|
2023-01-05 23:33:49 +00:00
|
|
|
// highlight-end
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
### iOS
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
Relaunch the app with `ns run ios`
|
2023-01-05 23:33:49 +00:00
|
|
|
|
|
|
|
The app can be tested with the following sequence in the simulator:
|
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
- Tap "Export File". A dialog will print where the file was written
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
- Open the file with a spreadsheet editor.
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
After the header row, insert a row with cell A2 = 0, B2 = SheetJS, C2 = Library:
|
2023-01-05 23:33:49 +00:00
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
```
|
|
|
|
id | name | role
|
|
|
|
0 | SheetJS | Library
|
|
|
|
1 | Ter Stegen | Goalkeeper
|
|
|
|
3 | Piqué | Defender
|
2023-01-05 23:33:49 +00:00
|
|
|
...
|
|
|
|
```
|
|
|
|
|
2023-04-03 09:09:59 +00:00
|
|
|
Restart the app after saving the file.
|
|
|
|
|
|
|
|
- Tap "Import File". A dialog will print the path of the file that was read.
|
2023-01-05 23:33:49 +00:00
|
|
|
The first item in the list will change:
|
|
|
|
|
|
|
|
![NativeScript Step 7](pathname:///mobile/nativescript7.png)
|
|
|
|
|