| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | --- | 
					
						
							|  |  |  | title: Quasar | 
					
						
							| 
									
										
										
										
											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: 3 | 
					
						
							|  |  |  | sidebar_custom_props: | 
					
						
							|  |  |  |   summary: VueJS + Web View | 
					
						
							|  |  |  | --- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-08 08:42:15 +00:00
										 |  |  | The "Complete Example" creates an app that looks like the screenshots below: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <table><thead><tr> | 
					
						
							|  |  |  |   <th><a href="#demo">iOS</a></th> | 
					
						
							|  |  |  |   <th><a href="#demo">Android</a></th> | 
					
						
							|  |  |  | </tr></thead><tbody><tr><td> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </td><td> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </td></tr></tbody></table> | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ### Integration Details
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  | This demo will use the Quasar ViteJS starter project with VueJS and Cordova. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | The complete solution uses `cordova-plugin-file` for file operations.  It can | 
					
						
							|  |  |  | be installed like any other Cordova plugin: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | cd src-cordova | 
					
						
							|  |  |  | cordova plugin add cordova-plugin-file | 
					
						
							|  |  |  | cd .. | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Reading data
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `q-file` component presents an API reminiscent of File Input elements: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```html | 
					
						
							|  |  |  | <q-file label="Load File" filled label-color="orange" @input="updateFile"/> | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When binding to the `input` element, the callback receives an `Event` object: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```ts | 
					
						
							|  |  |  | import { read } from 'xlsx'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // assuming `todos` is a standard VueJS `ref` | 
					
						
							|  |  |  | async function updateFile(v) { try { | 
					
						
							|  |  |  |   // `v.target.files[0]` is the desired file object | 
					
						
							|  |  |  |   const files = (v.target as HTMLInputElement).files; | 
					
						
							|  |  |  |   if(!files || files.length == 0) return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // read first file | 
					
						
							|  |  |  |   const wb = read(await files[0].arrayBuffer()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // get data of first worksheet as an array of objects | 
					
						
							|  |  |  |   const data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // update state | 
					
						
							|  |  |  |   todos.value = data.map(row => ({id: row.Index, content: row.Name})); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } catch(e) { console.log(e); } } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Writing data
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The API is shaped like the File and Directory Entries API.  For clarity, since | 
					
						
							|  |  |  | the code is a "pyramid of doom", the error handlers are omitted: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```ts | 
					
						
							|  |  |  | import { write } from 'xlsx'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // on iOS and android, `XLSX.write` with type "buffer" returns a `Uint8Array` | 
					
						
							|  |  |  | const u8: Uint8Array = write(wb, {bookType: "xlsx", type: "buffer"}); | 
					
						
							|  |  |  | // Request filesystem access for persistent storage | 
					
						
							|  |  |  | window.requestFileSystem(window.PERSISTENT, 0, function(fs) { | 
					
						
							|  |  |  |   // Request a handle to "SheetJSQuasar.xlsx", making a new file if necessary | 
					
						
							|  |  |  |   fs.root.getFile("SheetJSQuasar.xlsx", {create: true}, entry => { | 
					
						
							|  |  |  |     // Request a FileWriter for writing data | 
					
						
							|  |  |  |     entry.createWriter(writer => { | 
					
						
							|  |  |  |       // The FileWriter API needs an actual Blob | 
					
						
							|  |  |  |       const data = new Blob([u8], {type: "application/vnd.ms-excel"}); | 
					
						
							|  |  |  |       // This callback is called if the write is successful | 
					
						
							|  |  |  |       writer.onwriteend = () => { | 
					
						
							|  |  |  |         // TODO: show a dialog | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |       // writer.onerror will be invoked if there is an error in writing | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // write the data | 
					
						
							|  |  |  |       writer.write(data); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Demo
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  | This demo was tested on an Intel Mac on 2023 April 08. `create-quasar@1.1.2` | 
					
						
							|  |  |  | was installed during app creation.  The app used Quasar version `2.11.10`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The iOS simulator runs iOS 16.2 on an iPhone 14 Pro Max. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The Android simulator runs Android 12.0 (S) API 31 on a Pixel 3. | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The demo draws from the ViteJS example.  Familiarity with VueJS and TypeScript | 
					
						
							|  |  |  | is assumed. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 0) Ensure all of the dependencies are installed.  Install the CLI globally: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | npm i -g @quasar/cli cordova | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | (you may need to run `sudo npm i -g` if there are permission issues) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 1) Create a new app: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | npm init quasar | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <!-- spellchecker-disable --> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When prompted: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - "What would you like to build?": `App with Quasar CLI` | 
					
						
							|  |  |  | - "Project folder": `SheetJSQuasar` | 
					
						
							|  |  |  | - "Pick Quasar version": `Quasar v2 (Vue 3 | latest and greatest)` | 
					
						
							|  |  |  | - "Pick script type": `Typescript` | 
					
						
							|  |  |  | - "Pick Quasar App CLI variant": `Quasar App CLI with Vite` | 
					
						
							|  |  |  | - "Package name": (just press enter, it will use the default `sheetjsquasar` | 
					
						
							|  |  |  | - "Project product name": `SheetJSQuasar` | 
					
						
							|  |  |  | - "Project description": `SheetJS + Quasar` | 
					
						
							|  |  |  | - "Author": (just press enter, it will use your git config settings) | 
					
						
							|  |  |  | - "Pick a Vue component style": `Composition API` | 
					
						
							|  |  |  | - "Pick your CSS preprocessor": `None` | 
					
						
							|  |  |  | - "Check the features needed for your project": Deselect everything | 
					
						
							|  |  |  | - "Install project dependencies": `No` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2) Install dependencies: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <!-- spellchecker-enable --> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-07 13:58:36 +00:00
										 |  |  | <CodeBlock language="bash">{`\ | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | cd SheetJSQuasar | 
					
						
							|  |  |  | npm i | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  | 3) Set up Cordova: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | quasar mode add cordova | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When prompted, enter the app id `org.sheetjs.quasar`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | It will create a new `src-cordova` folder. Continue in that folder: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | cd src-cordova | 
					
						
							|  |  |  | cordova platform add ios | 
					
						
							|  |  |  | cordova plugin add cordova-plugin-wkwebview-engine | 
					
						
							|  |  |  | cordova plugin add cordova-plugin-file | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 18:04:23 +00:00
										 |  |  | :::note pass | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | If there is an error `Could not load API for iOS project`, it needs to be reset: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | cordova platform rm ios | 
					
						
							|  |  |  | cordova platform add ios | 
					
						
							|  |  |  | cordova plugin add cordova-plugin-file | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Return to the project directory: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | cd .. | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 4) Start the development server: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | quasar dev -m ios | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::caution | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If the app is blank or not refreshing, delete the app and close the simulator, | 
					
						
							|  |  |  | then restart the development process. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 5) Add the Dialog plugin to `quasar.config.js`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js title="quasar.config.js" | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  |     framework: { | 
					
						
							|  |  |  |       config: {}, | 
					
						
							|  |  |  | // ... | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  |       // Quasar plugins | 
					
						
							|  |  |  |       // highlight-next-line | 
					
						
							|  |  |  |       plugins: ['Dialog'] | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  |     }, | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  | 6) In the template section of `src/pages/IndexPage.vue`, replace the example | 
					
						
							|  |  |  |    with a Table, Save button and Load file picker component: | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```html title="src/pages/IndexPage.vue" | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  | <template> | 
					
						
							|  |  |  |   <q-page class="row items-center justify-evenly"> | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  |     <!-- highlight-start --> | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  |     <q-table :rows="todos" /> | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  |     <q-btn-group> | 
					
						
							|  |  |  |       <q-file label="Load File" filled label-color="orange" @input="updateFile"/> | 
					
						
							|  |  |  |       <q-btn label="Save File" @click="saveFile" /> | 
					
						
							|  |  |  |     </q-btn-group> | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:40 +00:00
										 |  |  |     <!-- highlight-end --> | 
					
						
							|  |  |  |   </q-page> | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | </template> | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This uses two functions that should be added to the component script: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```ts title="src/pages/IndexPage.vue" | 
					
						
							|  |  |  |     const meta = ref<Meta>({ | 
					
						
							|  |  |  |       totalCount: 1200 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | // highlight-start | 
					
						
							|  |  |  |     function saveFile() { | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  |     async function updateFile(v: Event) { | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     return { todos, meta, saveFile, updateFile }; | 
					
						
							|  |  |  | // highlight-end | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The app should now show two buttons at the bottom: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::caution | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If the app is blank or not refreshing, delete the app and close the simulator, | 
					
						
							|  |  |  | then restart the development process. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 7) Wire up the `updateFile` function: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```ts title="src/pages/IndexPage.vue" | 
					
						
							|  |  |  | import { defineComponent, ref } from 'vue'; | 
					
						
							|  |  |  | // highlight-start | 
					
						
							|  |  |  | import { read, write, utils } from 'xlsx'; | 
					
						
							|  |  |  | import { useQuasar } from 'quasar'; | 
					
						
							|  |  |  | // highlight-end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default defineComponent({ | 
					
						
							|  |  |  | // ... | 
					
						
							|  |  |  | // highlight-start | 
					
						
							|  |  |  |     const $q = useQuasar(); | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  |     function dialogerr(e: Error) { $q.dialog({title: "Error!", message: e.message || String(e)}); } | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | // highlight-end | 
					
						
							|  |  |  |     function saveFile() { | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  |     async function updateFile(v: Event) { | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | // highlight-start | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         const files = (v.target as HTMLInputElement).files; | 
					
						
							|  |  |  |         if(!files || files.length == 0) return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const wb = read(await files[0].arrayBuffer()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  |         const data = utils.sheet_to_json<any>(wb.Sheets[wb.SheetNames[0]]); | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  |         todos.value = data.map(row => ({id: row.Index, content: row.Name})); | 
					
						
							|  |  |  |       } catch(e) { dialogerr(e); } | 
					
						
							|  |  |  | // highlight-end | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To test that reading works: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Download <https://sheetjs.com/pres.numbers> | 
					
						
							|  |  |  | - In the simulator, click the Home icon to return to the home screen | 
					
						
							|  |  |  | - Click on the "Files" icon | 
					
						
							|  |  |  | - Click and drag `pres.numbers` from a Finder window into the simulator. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Make sure "On My iPhone" is highlighted and select "Save" | 
					
						
							|  |  |  | - Click the Home icon again then select the `SheetJSQuasar` app | 
					
						
							|  |  |  | - Click the "Load" button, then select "Choose File" and select `pres`: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  | Once selected, the screen should refresh with new contents. | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 8) Wire up the `saveFile` function: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  | ```ts title="src/pages/IndexPage.vue" | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  |     function saveFile() { | 
					
						
							|  |  |  | // highlight-start | 
					
						
							|  |  |  |       /* generate workbook from state */ | 
					
						
							|  |  |  |       const ws = utils.json_to_sheet(todos.value); | 
					
						
							|  |  |  |       const wb = utils.book_new(); | 
					
						
							|  |  |  |       utils.book_append_sheet(wb, ws, "SheetJSQuasar"); | 
					
						
							|  |  |  |       const u8: Uint8Array = write(wb, {bookType: "xlsx", type: "buffer"}); | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  |       const dir: string = $q.cordova.file.documentsDirectory || $q.cordova.file.externalApplicationStorageDirectory; | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       /* save to file */ | 
					
						
							|  |  |  |       window.requestFileSystem(window.PERSISTENT, 0, function(fs) { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           fs.root.getFile("SheetJSQuasar.xlsx", {create: true}, entry => { | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  |             const msg = `File stored at ${dir} ${entry.fullPath}`; | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  |             entry.createWriter(writer => { | 
					
						
							|  |  |  |               try { | 
					
						
							|  |  |  |                 const data = new Blob([u8], {type: "application/vnd.ms-excel"}); | 
					
						
							|  |  |  |                 writer.onwriteend = () => { | 
					
						
							|  |  |  |                   try { | 
					
						
							|  |  |  |                     $q.dialog({title: "Success!", message: msg}); | 
					
						
							|  |  |  |                   } catch(e) { dialogerr(e); } | 
					
						
							|  |  |  |                 }; | 
					
						
							|  |  |  |                 writer.onerror = dialogerr; | 
					
						
							|  |  |  |                 writer.write(data); | 
					
						
							|  |  |  |               } catch(e) { dialogerr(e); } | 
					
						
							|  |  |  |             }, dialogerr); | 
					
						
							|  |  |  |           }, dialogerr); | 
					
						
							|  |  |  |         } catch(e) { dialogerr(e) } | 
					
						
							|  |  |  |       }, dialogerr); | 
					
						
							|  |  |  | // highlight-end | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The page should revert to the old contents. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To test that writing works: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Click "Save File".  You will see a popup with a location: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Find the file and verify the contents are correct.  Run in a new terminal: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | find ~/Library/Developer/CoreSimulator -name SheetJSQuasar.xlsx | | 
					
						
							|  |  |  |   while read x; do echo "$x"; npx xlsx-cli "$x"; done | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Since the contents reverted, you should see | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | SheetJSQuasar | 
					
						
							|  |  |  | id,content | 
					
						
							|  |  |  | 1,ct1 | 
					
						
							|  |  |  | 2,ct2 | 
					
						
							|  |  |  | 3,ct3 | 
					
						
							|  |  |  | 4,ct4 | 
					
						
							|  |  |  | 5,ct5 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Use "Load File" to select `pres.numbers` again.  Wait for the app to refresh. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Click "Save File", then re-run the command: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | find ~/Library/Developer/CoreSimulator -name SheetJSQuasar.xlsx | | 
					
						
							|  |  |  |   while read x; do echo "$x"; npx xlsx-cli "$x"; done | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The contents from `pres.numbers` should show up now, with a new header row: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | SheetJSQuasar | 
					
						
							|  |  |  | id,content | 
					
						
							|  |  |  | 42,Bill Clinton | 
					
						
							|  |  |  | 43,GeorgeW Bush | 
					
						
							|  |  |  | 44,Barack Obama | 
					
						
							|  |  |  | 45,Donald Trump | 
					
						
							|  |  |  | 46,Joseph Biden | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  | **Android** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 9) Create the Android project: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | cd src-cordova | 
					
						
							|  |  |  | cordova platform add android | 
					
						
							|  |  |  | cd .. | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 10) Start the simulator: | 
					
						
							| 
									
										
										
										
											2023-01-05 23:33:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-08 08:42:15 +00:00
										 |  |  | ```bash | 
					
						
							|  |  |  | quasar dev -m android | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In local testing, the Quasar build process threw an error: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  |   java.lang.IllegalArgumentException: Unsupported class file major version 63 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This was resolved by rolling back to Java 1.8 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To test that reading works: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Click and drag `pres.numbers` from a Finder window into the simulator. | 
					
						
							|  |  |  | - Tap "Load", tap the `≡` icon, tap "Downloads" and select `pres.numbers`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To test that writing works: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Tap "Save File".  You will see a popup with a location. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - Pull the file from the simulator and verify the contents: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | adb exec-out run-as org.sheetjs.quasar cat files/files/SheetJSQuasar.xlsx > /tmp/SheetJSQuasar.xlsx | 
					
						
							|  |  |  | npx xlsx-cli /tmp/SheetJSQuasar.xlsx | 
					
						
							|  |  |  | ``` |