Please create demo for OpenUI5 #20

Open
opened 2024-10-17 05:51:30 +00:00 by mydoghasfleas · 3 comments

Please create a demo for OpenUI5:

(OpenUI5 is the open source framework maintained by SAP SE that is used as a base for their UI5 enterprise version: https://ui5.sap.com/).

Please create a demo for OpenUI5: - https://openui5.org/ - https://github.com/SAP/openui5 (OpenUI5 is the open source framework maintained by SAP SE that is used as a base for their UI5 enterprise version: https://ui5.sap.com/).
Owner

Here's a sketch after spending half an hour looking at the official documentation. Any sort of feedback on the OpenUI5 side would be appreciated, as there are some opportunities for improvement.

tl;dr: vendor script, load using sap.ui.define but name the function argument _XLSX, reference XLSX in the component function body.

OpenUI5 Starter

The Worklist App Tutorial creates a table. The code for step 4 is at https://sdk.openui5.org/entity/sap.m.tutorial.worklist/sample/sap.m.tutorial.worklist.04

  1. Download the code sample by opening https://sdk.openui5.org/entity/sap.m.tutorial.worklist/sample/sap.m.tutorial.worklist.04 in a web browser and clicking the "Download" button. It will attempt to download a ZIP file

  2. Extract the zip file and open a terminal window in the folder

  3. Install dependencies:

npm i
  1. Start the server:
npm start

The tool will display a URL:

Server started
URL: http://localhost:8081
  1. Open /test/mockServer.html for the displayed URL. For example, if the URL is http://localhost:6969, then the correct page is http://localhost:6969/test/mockServer.html

When this was tested, there were 14 rows of data in the table.

Require SheetJS

  1. Download the standalone script and move to the webapp folder:
curl -Lo webapp/xlsx.full.min.js https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js
  1. Require "./xlsx.full.min"in webapp/Component.js (no .js extension):
sap.ui.define([
	"sap/ui/core/UIComponent",
	"sap/ui/Device",
	"./model/models",
	"./controller/ErrorHandler",
	"./xlsx.full.min" // <-- add this line and the comma in the previous line
], function (UIComponent, Device, models, ErrorHandler, _XLSX) { // <-- add the last argument _XLSX, not XLSX!
  1. In the same script, add alert(XLSX.version); after the "use strict" line:
], function (UIComponent, Device, models, ErrorHandler, _XLSX) {
	"use strict";
	alert(XLSX); // <-- this line

	return UIComponent.extend("mycompany.myapp.MyWorklistApp.Component", {
  1. Stop and restart the server (CTRL+C then run npm start)

  2. Open /test/mockServer.html for the displayed URL.

If the SheetJS library is properly loaded, the page will alert with the library version number (currently 0.20.3)

Button Callback

In this example, we will reuse the existing share button in the top-right corner. It is defined in webapp/view/Worklist.view.xml as follows:

		<semantic:sendEmailAction>
			<semantic:SendEmailAction id="shareEmail" press=".onShareEmailPress"/>
		</semantic:sendEmailAction>

The event handler is onShareEmailPress in `webapp/controller/BaseController.js

  1. Require "../xlsx.full.min"in webapp/controller/BaseController.js (note: it needs to be ../ since the script is one folder up):
sap.ui.define([
	"sap/ui/core/mvc/Controller",
	"sap/ui/core/UIComponent",
	"sap/m/library",
	"../xlsx.full.min" // <--
], function (Controller, UIComponent, mobileLibrary, _XLSX) { // <--
  1. In the same script, replace the implementation of onShareEmailPress:
		onShareEmailPress : function () {
			alert(XLSX.version);
		}
  1. Stop and restart the server, then open the mockServer page again.

When you click the mail icon, the page will alert with the SheetJS version number.

Export Data

It appears that, from the controller, this.byId("table").getBinding("items").akeys is a list of the keys of the displayed rows and this.byId("table").getBinding("items").oModel.oData is an object whose values are the underlying row data objects.

			const items = this.byId("table").getBinding("items");
			const aoo = items.aKeys.map(r => items.oModel.oData[r]);

aoo will be an Array of Objects. json_to_sheet will generate a worksheet.

  1. In the same script, replace the implementation of onShareEmailPress:
		onShareEmailPress : function () {
			const items = this.byId("table").getBinding("items");
			const aoo = items.aKeys.map(r => items.oModel.oData[r]);
			const ws = XLSX.utils.json_to_sheet(aoo);
			const wb = XLSX.utils.book_new(ws, "Data");
			XLSX.writeFile(wb, "SheetJSOpenUI5.xlsx");
		}
  1. Stop and restart the server, then open the mockServer page again.

When you click the mail icon, the page will attempt to export the data.

Note that the extra columns are present in the oData objects. UI5 likely has an API for getting the relevant data.

Here's a sketch after spending half an hour looking at the official documentation. Any sort of feedback on the OpenUI5 side would be appreciated, as there are some opportunities for improvement. tl;dr: vendor script, load using `sap.ui.define` but name the function argument `_XLSX`, reference `XLSX` in the component function body. ### OpenUI5 Starter The [Worklist App Tutorial](https://sdk.openui5.org/topic/85ec3a9454ac4eb1a901745e773844d3) creates a table. The code for step 4 is at https://sdk.openui5.org/entity/sap.m.tutorial.worklist/sample/sap.m.tutorial.worklist.04 1) Download the code sample by opening https://sdk.openui5.org/entity/sap.m.tutorial.worklist/sample/sap.m.tutorial.worklist.04 in a web browser and clicking the "Download" button. It will attempt to download a ZIP file 2) Extract the zip file and open a terminal window in the folder 3) Install dependencies: ```bash npm i ``` 4) Start the server: ```bash npm start ``` The tool will display a URL: ``` Server started URL: http://localhost:8081 ``` 5) Open `/test/mockServer.html` for the displayed URL. For example, if the URL is `http://localhost:6969`, then the correct page is `http://localhost:6969/test/mockServer.html` When this was tested, there were 14 rows of data in the table. ### Require SheetJS 6) Download the standalone script and move to the `webapp` folder: ```bash curl -Lo webapp/xlsx.full.min.js https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js ``` 7) Require `"./xlsx.full.min"`in `webapp/Component.js` (no `.js` extension): ```js sap.ui.define([ "sap/ui/core/UIComponent", "sap/ui/Device", "./model/models", "./controller/ErrorHandler", "./xlsx.full.min" // <-- add this line and the comma in the previous line ], function (UIComponent, Device, models, ErrorHandler, _XLSX) { // <-- add the last argument _XLSX, not XLSX! ``` 8) In the same script, add `alert(XLSX.version);` after the `"use strict"` line: ```js ], function (UIComponent, Device, models, ErrorHandler, _XLSX) { "use strict"; alert(XLSX); // <-- this line return UIComponent.extend("mycompany.myapp.MyWorklistApp.Component", { ``` 9) Stop and restart the server (`CTRL+C` then run `npm start`) 10) Open `/test/mockServer.html` for the displayed URL. If the SheetJS library is properly loaded, the page will alert with the library version number (currently `0.20.3`) ### Button Callback In this example, we will reuse the existing share button in the top-right corner. It is defined in `webapp/view/Worklist.view.xml` as follows: ```xml <semantic:sendEmailAction> <semantic:SendEmailAction id="shareEmail" press=".onShareEmailPress"/> </semantic:sendEmailAction> ``` The event handler is `onShareEmailPress` in `webapp/controller/BaseController.js 11) Require `"../xlsx.full.min"`in `webapp/controller/BaseController.js` (note: it needs to be `../` since the script is one folder up): ```js sap.ui.define([ "sap/ui/core/mvc/Controller", "sap/ui/core/UIComponent", "sap/m/library", "../xlsx.full.min" // <-- ], function (Controller, UIComponent, mobileLibrary, _XLSX) { // <-- ``` 12) In the same script, replace the implementation of `onShareEmailPress`: ```js onShareEmailPress : function () { alert(XLSX.version); } ``` 13) Stop and restart the server, then open the `mockServer` page again. When you click the mail icon, the page will alert with the SheetJS version number. ### Export Data It appears that, from the controller, `this.byId("table").getBinding("items").akeys` is a list of the keys of the displayed rows and `this.byId("table").getBinding("items").oModel.oData` is an object whose values are the underlying row data objects. ```js const items = this.byId("table").getBinding("items"); const aoo = items.aKeys.map(r => items.oModel.oData[r]); ``` `aoo` will be an [Array of Objects](https://docs.sheetjs.com/docs/api/utilities/array#arrays-of-objects). [`json_to_sheet`](https://docs.sheetjs.com/docs/api/utilities/array#array-of-objects-input) will generate a worksheet. 14) In the same script, replace the implementation of `onShareEmailPress`: ```js onShareEmailPress : function () { const items = this.byId("table").getBinding("items"); const aoo = items.aKeys.map(r => items.oModel.oData[r]); const ws = XLSX.utils.json_to_sheet(aoo); const wb = XLSX.utils.book_new(ws, "Data"); XLSX.writeFile(wb, "SheetJSOpenUI5.xlsx"); } ``` 15) Stop and restart the server, then open the `mockServer` page again. When you click the mail icon, the page will attempt to export the data. Note that the extra columns are present in the oData objects. UI5 likely has an API for getting the relevant data.
sheetjs reopened this issue 2024-10-18 22:14:26 +00:00
Owner

The extra columns appear to fall in two categories:

  • "deferred" fields whose data haven't been pulled
  • "references" to other data that may have been pulled

For the purposes of the demo, suppressing those fields suffices.

getCurrentContexts is apparently the recommended way of pulling the data objects:

const data = athis.byId("table").getBinding("items").getCurrentContexts()

Each object must be inspected and the deferred and reference objects must be removed.

To avoid mutating the object directly, fromEntries / entries is the best approach. An example is included in the caution admonition in "Array of Objects Input"

const filtered_object = Object.fromEntries(Object.entries(context.getObject()).flatMap(r => {
  // r[0] is the key, r[1] is the value
  if(typeof r[1] == "object") {
    if(r[1].__deferred) return; // skip deferred fields
    if(r[1].__ref) return; // skip references
  }
  return [r];
}).filter(r => r)));
// the filter removes the undefined data (deferred and reference fields)

That step would need to be run for each data object, resulting in the following snippet to generate an array of arrays:

  const aoo = this.byId("table").getBinding("items").getCurrentContexts().map(ctx => Object.fromEntries(Object.entries(ctx.getObject()).flatMap(r => {
    if(typeof r[1] == "object") {
      if(r[1].__deferred) return; // skip deferred fields
      if(r[1].__ref) return; // skip references
    }
    return [r];
  }).filter(r => r)));

If you have UI5 experience and find this example consistent with UI5 best practices, we'll look into adding it to the documentation.

The extra columns appear to fall in two categories: - "deferred" fields whose data haven't been pulled - "references" to other data that may have been pulled For the purposes of the demo, suppressing those fields suffices. `getCurrentContexts` is apparently the recommended way of pulling the data objects: ```js const data = athis.byId("table").getBinding("items").getCurrentContexts() ``` Each object must be inspected and the deferred and reference objects must be removed. To avoid mutating the object directly, `fromEntries` / `entries` is the best approach. [An example is included in the caution admonition in "Array of Objects Input"](https://docs.sheetjs.com/docs/api/utilities/array#array-of-objects-input) ```js const filtered_object = Object.fromEntries(Object.entries(context.getObject()).flatMap(r => { // r[0] is the key, r[1] is the value if(typeof r[1] == "object") { if(r[1].__deferred) return; // skip deferred fields if(r[1].__ref) return; // skip references } return [r]; }).filter(r => r))); // the filter removes the undefined data (deferred and reference fields) ``` That step would need to be run for each data object, resulting in the following snippet to generate an array of arrays: ```js const aoo = this.byId("table").getBinding("items").getCurrentContexts().map(ctx => Object.fromEntries(Object.entries(ctx.getObject()).flatMap(r => { if(typeof r[1] == "object") { if(r[1].__deferred) return; // skip deferred fields if(r[1].__ref) return; // skip references } return [r]; }).filter(r => r))); ``` If you have UI5 experience and find this example consistent with UI5 best practices, we'll look into adding it to the documentation.
Contributor

@sheetjs Would you like this added to the main docs? I'd be happy to help clean this up and create OpenUI5 demo.

@sheetjs Would you like this added to the main docs? I'd be happy to help clean this up and create OpenUI5 demo.
Sign in to join this conversation.
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: sheetjs/docs.sheetjs.com#20
No description provided.