From 95f65248a0f7b3c344881831067365c0aef571fb Mon Sep 17 00:00:00 2001 From: SheetJS Date: Mon, 1 Aug 2022 01:34:23 -0400 Subject: [PATCH] angularjs --- .../03-demos/10-database.md | 170 +++++++++++++++ .../04-getting-started/03-demos/12-legacy.md | 136 +++++++++++- .../04-getting-started/03-demos/14-grid.md | 153 +++++++++++++ .../docs/04-getting-started/03-demos/index.md | 5 +- docz/static/angularjs/index.html | 78 +++++++ docz/static/angularjs/ui-grid.html | 201 ++++++++++++++++++ docz/static/cdg/index.html | 167 +++++++++++++++ 7 files changed, 906 insertions(+), 4 deletions(-) create mode 100644 docz/docs/04-getting-started/03-demos/14-grid.md create mode 100644 docz/static/angularjs/index.html create mode 100644 docz/static/angularjs/ui-grid.html create mode 100644 docz/static/cdg/index.html diff --git a/docz/docs/04-getting-started/03-demos/10-database.md b/docz/docs/04-getting-started/03-demos/10-database.md index 1919cf3..0058705 100644 --- a/docz/docs/04-getting-started/03-demos/10-database.md +++ b/docz/docs/04-getting-started/03-demos/10-database.md @@ -563,6 +563,176 @@ for(var i = 0; i < localForage.length; ++i) aoo.push(JSON.parse(await localForag const wb = XLSX.utils.json_to_sheet(aoo); ``` +### Other SQL Databases + +The `generate_sql` function from ["Building Schemas from Worksheets"](#building-schemas-from-worksheets) +can be adapted to generate SQL statements for a variety of databases, including: + +**PostgreSQL** + +The `pg` connector library was tested against the `generate_sql` output as-is. + +The `rows` property of a query result is an array of objects that plays nice +with `json_to_sheet`: + +```js +const aoa = await connection.query(`SELECT * FROM DataTable`).rows; +const worksheet = XLSX.utils.json_to_sheet(aoa); +``` + +**MySQL / MariaDB** + +The `mysql2` connector library was tested. The differences are shown below, +primarily stemming from the different quoting requirements and field types. + +
Differences (click to show) + +```js +// highlight-start +// define mapping between determined types and MySQL types +const PG = { "n": "REAL", "s": "TEXT", "b": "TINYINT" }; +// highlight-end + +function generate_sql(ws, wsname) { + + // generate an array of objects from the data + const aoo = XLSX.utils.sheet_to_json(ws); + + // types will map column headers to types, while hdr holds headers in order + const types = {}, hdr = []; + + // loop across each row object + aoo.forEach(row => + // Object.entries returns a row of [key, value] pairs. Loop across those + Object.entries(row).forEach(([k,v]) => { + + // If this is first time seeing key, mark unknown and append header array + if(!types[k]) { types[k] = "?"; hdr.push(k); } + + // skip null and undefined + if(v == null) return; + + // check and resolve type + switch(typeof v) { + case "string": // strings are the broadest type + types[k] = "s"; break; + case "number": // if column is not string, number is the broadest type + if(types[k] != "s") types[k] = "n"; break; + case "boolean": // only mark boolean if column is unknown or boolean + if("?b".includes(types[k])) types[k] = "b"; break; + default: types[k] = "s"; break; // default to string type + } + }) + ); + + // The final array consists of the CREATE TABLE query and a series of INSERTs + return [ + // generate CREATE TABLE query and return batch + // highlight-next-line + `CREATE TABLE ${wsname} (${hdr.map(h => + // highlight-next-line + `${h} ${PG[types[h]]}` + ).join(", ")});` + ].concat(aoo.map(row => { // generate INSERT query for each row + // entries will be an array of [key, value] pairs for the data in the row + const entries = Object.entries(row); + // fields will hold the column names and values will hold the values + const fields = [], values = []; + // check each key/value pair in the row + entries.forEach(([k,v]) => { + // skip null / undefined + if(v == null) return; + // highlight-next-line + fields.push(`${k}`); + // when the field type is numeric, `true` -> 1 and `false` -> 0 + if(types[k] == "n") values.push(typeof v == "boolean" ? (v ? 1 : 0) : v); + // otherwise, + // highlight-next-line + else values.push(`"${v.toString().replaceAll('"', '""')}"`); + }) + if(fields.length) return `INSERT INTO \`${wsname}\` (${fields.join(", ")}) VALUES (${values.join(", ")})`; + })).filter(x => x); // filter out skipped rows +} +``` + +
+ +The first property of a query result is an array of objects that plays nice +with `json_to_sheet`: + +```js +const aoa = await connection.query(`SELECT * FROM DataTable`)[0]; +const worksheet = XLSX.utils.json_to_sheet(aoa); +``` + + +### Query Builders + +Query builders are designed to simplify query generation and normalize field +types and other database minutiae. + +**Knex** + +The result of a `SELECT` statement is an array of objects: + +```js +const aoo = await connection.select("*").from("DataTable"); +const worksheet = XLSX.utils.json_to_sheet(aoa); +``` + +Knex wraps primitive types when creating a table. `generate_sql` takes a `knex` +connection object and uses the API: + +
Generating a Table (click to show) + +```js +// define mapping between determined types and Knex types +const PG = { "n": "float", "s": "text", "b": "boolean" }; + +async function generate_sql(knex, ws, wsname) { + + // generate an array of objects from the data + const aoo = XLSX.utils.sheet_to_json(ws); + + // types will map column headers to types, while hdr holds headers in order + const types = {}, hdr = []; + + // loop across each row object + aoo.forEach(row => + // Object.entries returns a row of [key, value] pairs. Loop across those + Object.entries(row).forEach(([k,v]) => { + + // If this is first time seeing key, mark unknown and append header array + if(!types[k]) { types[k] = "?"; hdr.push(k); } + + // skip null and undefined + if(v == null) return; + + // check and resolve type + switch(typeof v) { + case "string": // strings are the broadest type + types[k] = "s"; break; + case "number": // if column is not string, number is the broadest type + if(types[k] != "s") types[k] = "n"; break; + case "boolean": // only mark boolean if column is unknown or boolean + if("?b".includes(types[k])) types[k] = "b"; break; + default: types[k] = "s"; break; // default to string type + } + }) + ); + + await knex.schema.dropTableIfExists(wsname); + await knex.schema.createTable(wsname, (table) => { hdr.forEach(h => { table[PG[types[h]] || "text"](h); }); }); + for(let i = 0; i < aoo.length; ++i) { + if(!aoo[i] || !Object.keys(aoo[i]).length) continue; + try { await knex.insert(aoo[i]).into(wsname); } catch(e) {} + } + return knex; +} +``` + +
+ ### MongoDB Structured Collections diff --git a/docz/docs/04-getting-started/03-demos/12-legacy.md b/docz/docs/04-getting-started/03-demos/12-legacy.md index 830bbf6..90c87c2 100644 --- a/docz/docs/04-getting-started/03-demos/12-legacy.md +++ b/docz/docs/04-getting-started/03-demos/12-legacy.md @@ -20,6 +20,135 @@ designed to be referenced with ` +``` + +**Previewing Data** + +The HTML document needs a container element: + +```html +
+``` + +Grid initialization is a one-liner: + +```js +var grid = canvasDatagrid({ + parentNode: document.getElementById('gridctr'), + data: [] +}); +``` + +For large data sets, it's necessary to constrain the size of the grid. + +```js +grid.style.height = '100%'; +grid.style.width = '100%'; +``` + +Once the workbook is read and the worksheet is selected, assigning the data +variable automatically updates the view: + +```js +grid.data = XLSX.utils.sheet_to_json(ws, {header:1}); +``` + +This demo previews the first worksheet. + +**Editing** + +`canvas-datagrid` handles the entire edit cycle. No intervention is necessary. + +**Saving Data** + +`grid.data` is immediately readable and can be converted back to a worksheet. +Some versions return an array-like object without the length, so a little bit of +preparation may be needed: + +```js +/* converts an array of array-like objects into an array of arrays */ +function prep(arr) { + var out = []; + for(var i = 0; i < arr.length; ++i) { + if(!arr[i]) continue; + if(Array.isArray(arr[i])) { out[i] = arr[i]; continue }; + var o = new Array(); + Object.keys(arr[i]).forEach(function(k) { o[+k] = arr[i][k] }); + out[i] = o; + } + return out; +} + +/* build worksheet from the grid data */ +var ws = XLSX.utils.aoa_to_sheet(prep(grid.data)); + +/* build up workbook */ +var wb = XLSX.utils.book_new(); +XLSX.utils.book_append_sheet(wb, ws, 'SheetJS'); + +/* generate download */ +XLSX.writeFile(wb, "SheetJS.xlsx"); +``` + +**Additional Features** + +This demo barely scratches the surface. The underlying grid component includes +many additional features including massive data streaming, sorting and styling. + + + + +### Angular UI Grid + +:::warning + +This UI Grid is for AngularJS, not the modern Angular. New projects should not +use AngularJS. This demo is included for legacy applications. + +The [AngularJS demo](./legacy#angularjs) covers more general strategies. + +::: + +[Click here for a live integration demo.](pathname:///angularjs/ui-grid.html) + +
Notes (click to show) + +The library does not provide any way to modify the import button, so the demo +includes a simple directive for a HTML File Input control. It also includes a +sample service for export which adds an item to the export menu. + +The demo `SheetJSImportDirective` follows the prescription from the README for +File input controls using `readAsArrayBuffer`, converting to a suitable +representation and updating the scope. + +`SheetJSExportService` exposes export functions for `XLSB` and `XLSX`. Other +file formats can be exported by changing the `bookType` variable. It grabs +values from the grid, builds an array of arrays, generates a workbook and forces +a download. By setting the `filename` and `sheetname` options in the `ui-grid` +options, the output can be controlled. + +
diff --git a/docz/docs/04-getting-started/03-demos/index.md b/docz/docs/04-getting-started/03-demos/index.md index 54d04e6..09e64bb 100644 --- a/docz/docs/04-getting-started/03-demos/index.md +++ b/docz/docs/04-getting-started/03-demos/index.md @@ -18,7 +18,7 @@ The demo projects include small runnable examples and short explainers. ### Frameworks -- [`Angular.JS`](https://github.com/SheetJS/SheetJS/tree/master/demos/angular/) +- [`Angular.JS`](./legacy#angularjs) - [`Angular 2+ and Ionic`](https://github.com/SheetJS/SheetJS/tree/master/demos/angular2/) - [`Knockout`](./legacy#knockout) - [`Meteor`](https://github.com/SheetJS/SheetJS/tree/master/demos/meteor/) @@ -27,10 +27,11 @@ The demo projects include small runnable examples and short explainers. ### Front-End UI Components -- [`canvas-datagrid`](https://github.com/SheetJS/SheetJS/tree/master/demos/datagrid/) +- [`canvas-datagrid`](./grid#canvas-datagrid) - [`x-spreadsheet`](https://github.com/SheetJS/SheetJS/tree/master/demos/xspreadsheet/) - [`react-data-grid`](https://github.com/SheetJS/SheetJS/tree/master/demos/react/modify/) - [`vue3-table-light`](https://github.com/SheetJS/SheetJS/tree/master/demos/vue/modify/) +- [`angular-ui-grid`](./grid#angular-ui-grid) ### Platforms and Integrations diff --git a/docz/static/angularjs/index.html b/docz/static/angularjs/index.html new file mode 100644 index 0000000..71ab290 --- /dev/null +++ b/docz/static/angularjs/index.html @@ -0,0 +1,78 @@ + + + + + + SheetJS + AngularJS + + + + + + + + +
+SheetJS + AngularJS demo
+
+The core library can be used as-is in AngularJS applications.
+The Community Edition README details some common use cases.
+We also have some more public demos
+
+This demo shows:
+- $http request for XLSX file and scope update with data
+- HTML table using ng-repeat
+- XLSX table export using `XLSX.utils.table_to_book`
+
+Sample Spreadsheet
+
+The table has hardcoded fields `Name` and `Index`.
+
+
+ +
+ + + + + + + +
NameIndex
{{row.Name}}{{row.Index}}
+ + + +
+ + + + + diff --git a/docz/static/angularjs/ui-grid.html b/docz/static/angularjs/ui-grid.html new file mode 100644 index 0000000..0a4f6b7 --- /dev/null +++ b/docz/static/angularjs/ui-grid.html @@ -0,0 +1,201 @@ + + + + + + SheetJS + AngularJS + ui-grid + + + + + + + + + + + + + + + +
+SheetJS + AngularJS demo
+
+The core library can be used as-is in AngularJS applications.
+The Community Edition README details some common use cases.
+We also have some more public demos
+
+This demo shows:
+- SheetJSExportService: a service for exporting data from a ui-grid
+- SheetJSImportDirective: a directive providing a file input button for import
+
+Sample Spreadsheet
+
+ +
+ +
+
+ + + + + + + + + diff --git a/docz/static/cdg/index.html b/docz/static/cdg/index.html new file mode 100644 index 0000000..055c3cf --- /dev/null +++ b/docz/static/cdg/index.html @@ -0,0 +1,167 @@ + + + + + + +SheetJS + canvas-datagrid Live Demo + + + +
+SheetJS Data Preview Live Demo
+
+canvas-datagrid component library
+
+Source Code Repo
+Issues?  Something look weird?  Click here and report an issue
+
+
Drop a spreadsheet file here to see sheet data
+ ... or click here to select a file + +Advanced Demo Options: +
+

+
+
+ + + + + + +