" Filter, Sort, Paging
/iwbep/cl_mgw_data_util=>filtering( EXPORTING it_select_options = it_filter_select_options
CHANGING ct_data = et_entityset ).
/iwbep/cl_mgw_data_util=>orderby( EXPORTING it_order = it_order
CHANGING ct_data = et_entityset ).
/iwbep/cl_mgw_data_util=>paging( EXPORTING is_paging = is_paging
CHANGING ct_data = et_entityset ).
Tag: OData
[ABAP] OData – Get the “low” value from a filter range
DATA(lt_filter) = io_tech_request_context->get_filter( )->get_filter_select_options( ).
IF line_exists( it_filter[ property = 'MYKEY' ] ).
DATA(lv_input) = it_filter[ property = 'MYKEY' ]-select_options[ 1 ]-low.
" ...
ENDIF.
[SAPUI5] Get and set properties of a binded model and submit changes
Get:
const oModel = this.getView().getModel()
const sPath = this.getView().getBindingContext().sPath
const sID = oModel.getProperty(sPath+"/ID")
Set:
const newID = "12345"
oModel.setProperty(sPath+"/ID", newID)
When using the set property function, you can now submit your changes this way:
// First check if there are any changes
if (!oModel.hasPendingChanges()) {
MessageToast.show("Nothing to do!")
return
}
// Now submit your changes
oModel.submitChanges({
success: () => MessageToast.show("Success!"),
error: (err) => alert(err)
})
This way is much more comfortable, than using oModel.update()
.
[CAP] SAPUI5 Filter using FilterOperator.Contains with oData V2
In my SAPUI5 Freesstyle frontend I created a search field above a list. In the searchfield handler I’m creating a filter with the provided query.
const sQuery = oEvent.getParameter("query");
new Filter("firstName", FilterOperator.Contains, sQuery);
Afterwards I’m binding the filter to my list to trigger the binding refresh. But when debugging the backend handler I noticed the following…
In my CAP on Read handler, the filter gets converted into a V4 compatible filter expression:
oData V4: $filter=contains(firstName,'Max')
As I’m forwarding the request to an external V2 oData API (SuccessFactors) this would not work, as for V2 the following filter syntax is needed:
oData V2: $filter=substringof('Max',firstName) eq true
As I could not find any solution to this problem, I manually passed my filter as custom property to my CAP Service and did a manual select.
Adding the custom property in the frontend in my searchfield handler:
onSearch: function (oEvent) {
if (oEvent.getParameters().refreshButtonPressed) {
this.onRefresh();
return;
}
let oBindingInfo = this._oList.getBindingInfo("items");
if (!oBindingInfo.parameters) oBindingInfo.parameters = {};
if (!oBindingInfo.parameters.custom) oBindingInfo.parameters.custom = {};
if (oEvent.getParameter("query")) {
oBindingInfo.parameters.custom.filter = "%" + oEvent.getParameter("query") + "%";
} else {
oBindingInfo.parameters.custom.filter = undefined
}
this._oList.bindItems(oBindingInfo);
}
My CAP handler with the filter handling:
const { Object } = srv.entities
const SF_Srv = await cds.connect.to('SF')
srv.on('READ', Object, async req => {
if (!req._queryOptions.filter) {
// share request context with the external service
return SF_Srv.tx(req).run(req.query);
} else {
//if filter provided, build manually a select statement using a where condition
let input = req._queryOptions.filter;
const tx = SF_Srv.transaction(req);
return await tx.run(
SELECT
.from(Object)
.where`firstName like ${input} or lastName like ${input}`)
}
})
As alternative you could also add the where condition directly to the query object:
const { Object } = srv.entities
const SF_Srv = await cds.connect.to('SF')
srv.on('READ', Object, async req => {
if (req._query.filter) {
//if filter provided, build manually a select statement using a where condition
let { query } = req
let input = req._queryOptions.filter
if (!query.SELECT.where) query.SELECT["where"] = []
query.SELECT.where.push(
{ ref: ['firstName'] }, 'like', { val: input }, "or",
{ ref: ['lastName'] }, 'like', { val: input }, "or",
{ ref: ['object'] }, 'like', { val: input })
}
// share request context with the external service
return SF_Srv.tx(req).run(req.query)
})
[OpenUI5] SAP Fiori elements add-on for OpenUI5 using an OData V4 service
Recently I found this blog post about the new SAP Fiori elements add-on for OpenUI5.
https://blogs.sap.com/2020/12/21/now-available-sap-fiori-elements-add-on-for-openui5/
It includes a little exercise to try it out for yourself. I wrote down all steps I had to make on my Linux Mint 20 installation.
These two links also helped me a lot.
https://github.com/sap-samples/cloud-cap-samples
https://cap.cloud.sap/docs/get-started/
Prerequisites (Node.js, Visual Studio Code, SAP Fiori tools, Git)
curl -sL https://deb.nodesource.com/setup_15.x | sudo -E bash -
sudo apt-get install -y nodejs
node --version
npm -v
Change npm’s default directory to prevent permission errors.
https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally
mkdir ~/.npm-global
npm config set prefix '~/.npm-global'
mkdir ~/.npm-global/lib
#add the following line to your .bashrc or .profile or .zshrc
export PATH=~/.npm-global/bin:$PATH
Step 1: Provide an OData V4 service
git clone https://github.com/sap-samples/cloud-cap-samples remote-odata-service
cd remote-odata-service
npm i
npm i -g @sap/cds-dk
cds watch fiori
Step 2: Generate a SAP Fiori elements List Report Object Page (LROP) app with Fiori tools
1. Open VSC, press Ctrl + P and search for > Fiori: Open Application Generator
2. Choose SAP Fiori elements application
In my case there was no default generator, so first I had to install it.
npm install -g @sap/generator-fiori-elements@latest
This can also be done directly in VSC.
3. Select List Report Object Page
4. Select Connect to an OData Service as Data source and enter as URL http://localhost:4004/browse
5. Choose Books as the Main entity and texts as Navigation entity
6. Complete the mandatory information module name (e.g. bookshop) and Project folder path for storing your app. Of course, you can also fill in the optional information.
Step 3: Make changes in package.json and ui5.yaml required for using OpenUI5
package.json
{
"name": "fiorielements_openui5",
"version": "0.0.1",
"private": true,
"sapux": true,
"description": "A Fiori application.",
"keywords": [
"ui5",
"openui5",
"sapui5"
],
"main": "webapp/index.html",
"scripts": {
"start": "fiori run --open index.html",
"start-local": "fiori run --config ./ui5-local.yaml --open index.html",
"build": "ui5 build -a --clean-dest --include-task=generateManifestBundle generateCachebusterInfo",
"deploy": "fiori add deploy-config"
},
"devDependencies": {
"@sap/ux-specification": "latest",
"@sap/ux-ui5-tooling": "1",
"@ui5/cli": "2.5.0",
"@ui5/fs": "2.0.1",
"@ui5/logger": "2.0.0"
},
"ui5": {
"dependencies": [
"@sap/ux-ui5-tooling",
"@sap/open.fe"
]
},
"dependencies": {
"@sap/open.fe": "1.85.0"
}
}
ui5.yaml
specVersion: '2.2'
metadata:
name: 'fiorielements_openui5'
type: application
framework:
name: OpenUI5
version: "1.85.0"
libraries:
- name: sap.m
- name: sap.ui.core
- name: sap.uxap
- name: themelib_sap_fiori_3
server:
customMiddleware:
- name: fiori-tools-proxy
afterMiddleware: compression
configuration:
ignoreCertError: false # If set to true, certificate errors will be ignored. E.g. self-signed certificates will be accepted
backend:
- path: /browse
url: http://localhost:4004
- name: fiori-tools-appreload
afterMiddleware: compression
configuration:
port: 35729
path: webapp
Step 4: Run the V4 application
cd ~/projects/fiorielements_openui5
npm i
npm start
Now http://localhost:8080/index.html should be opened in your browser.
“Note: Clicking on the Go button in List Report application might request user and password. Please enter user alice, no password.”
Finally I got my list items.
[ABAP Env] Create Data Model & OData Service
Recently I worked through the tutorial on creating a travel bookings app in the SAP Cloud Platform ABAP Environment.
Find a good introduction and overview on this topic here: Getting Started with ABAP in the Cloud – Part I
And the travel bookings app tutorial here: Getting Started with ABAP in the Cloud – Part II
These are my notes on the steps needed to create the data model and publish it as oData service.
# | Layer | Nomenclature | Description |
---|---|---|---|
1 | Database Table | ZTABLE | Place your raw data first |
2 | Data Definition (Interface View) | ZI_ | Relation between different tables (e.g. currency or text table) |
3 | Projection View (Consumption View) | ZC_ | Configure the UI depending on your scenario. Use different projection views for different usages of the same interface view and the same physical table. |
4 | Service Definition | ZSD_ | Expose the projection view (and underlying associations like currency, country…) as service |
5 | Service Binding | ZSB_ | How to we want to make the service available? Defines the binding type (OData V2 / OData V4) Activate it with the “Activate” Button within the editor window. Select the Entity and hit “Preview…” to see whtat we defined in our projection view. |
If you’ve done this, you are able to view the data in a generated Fiori Elements app. But if you also want to create, edit, delete data, you’ll have to add some behavior functionality.
6 | Behavior Definition on Data Definition | ZI_ | Created on top of the Data Definition. Will get the same name es the Data Definition. Implementation Type: Managed Defines the operations create, delete, edit. |
7 | Behavior Implementation on Definition View | ZBP_I_ | The code for the behavior… For the travel app tutorial, some logic for a generated unique key and field validation. The class inherits from cl_abap_behavior_handler. |
8 | Behavior Definition on Projection View | ZC_ | Created on top of the Projection View. Will get the same name es the Projection View. Defines the operations create, delete, edit. |
[Fiori] Transactions and Reports
SE38:
- /UI2/START_URL
- /UI2/START_TCODE
- /UI2/FLP_ADMIN_UI
SICF:
- Frontend-Services:
/sap/bc/ui5_ui5/sap/
- Backend-Services:
/sap/opu/odata/sap/
und/sap/bc/bsp/sap/
Tcodes:
sicf | Pflege des HTTP-Service-Baums (SAP Internet Communication Framework) | |
segw | SAP Gateway Service Builder | |
/n/iwbep/view_log | SAP Gateway Protokoll-Viewer | |
/n/iwfnd/gw_client | SAP Gateway Client | |
/n/iwfnd/apps_log | SAP Gateway Anwendungsprotokoll-Viewer | |
/n/iwfnd/error_log | SAP Gateway Fehlerprotokoll | |
/n/iwfnd/maint_service | Services aktivieren und verwalten | |
/n/iwfnd/cache_cleanup | Bereinigung des Gateway-Modellcache (Frontend) | |
/n/ui2/cust | Customizing für UI-Technologien | |
/n/ui2/flp | SAP Fiori Launchpad | |
/n/ui2/flc | SAP Fiori Launchpad – Prüfungen | |
/n/ui2/flia | Fiori Launchpad: Absichtsanalyse | |
/n/ui2/flpd_cust | Fiori Launchpad: Designer (mandantenüber.) | /n/ui2/flpcm_cust (3170196) |
/n/ui2/flpd_conf | Fiori Launchpad: Designer (mandantenabh.) | /n/ui2/flpcm_conf (3170196) |
/n/ui2/flpcm/cust | FLP-Content-Manager | |
/n/ui2/flpcm/conf | FLP-Content-Manager | |
/n/ui2/semobj | Semantisches Objekt definieren – Kunde | |
/n/ui2/semobj_sap | Semantisches Objekt definieren – SAP | |
/n/ui2/theme_designer | UI Theme Designer | |
swfvisu | Workflow Visualisierungs-Metadaten | |
swfvmd1 | Workflow Visualisierungs-Metadaten |