in this blog post, I would like to show you from scratch, how you can display hierarchical data in an SAP Fiori elements app based on CDS services provided by the SAP Cloud Application Programming Model.
I saw many questions internally and externally in the SAP community, asking how to do this.
The answer is not as straightforwards as one may think, as currently SAP Cloud Application Programming Model exposes out-of-the-box only OData V4 services serving SAP Fiori elements V4 UIs, but SAPUI5 does not support TreeTable control for OData V4.
The SAPUI5 documentation mentions the following disclaimer for OData V4 Model:
The
TreeTable
is not supported together with the SAPUI5 OData V4 model.
That means that we cannot perform this task directly using SAP Cloud Application Programming Model and OData V4.
That’s where the CDS OData V2 Adapter Proxy comes to the rescue. SAPUI5 supports TreeTable
for OData V2, and it’s often used in ABAP based applications. So, we need to convert the OData V4 services exposed by SAP Cloud Application Programming Model into an OData V2 service to be consumed by our hierarchy app.
For our setup following building blocks are used:
– SAP Cloud Application Programming Model
– Node.js
– OData V4
– OData V2
– CDS OData V2 Adapter Proxy
– SAP Fiori elements (V2)
– SAPUI5
– List Report (type “TreeTable”)
– @sap.hierarchy
annotations
In the following sections we go step-by-step through the setup, to be able to display
hierarchical data in SAP Fiori elements app using SAP Cloud Application Programming Model.
Setup Project
We start from scratch bootstrapping a CDS project for Node.js. We first need to install @sap/cds-dk to start the project initialization. In a terminal execute the following call.
Terminal:
npm install @sap/cds-dk --global
After the successful installation we can execute the cds initialization in an empty project directory.
Terminal:
cds init
The basic structure of a SAP Cloud Application Programming Model project is set up and we are ready to build our CDS data model.
To install the project dependencies (cds, express) we perform a npm install like this.
Terminal:
npm install
For simplicity we want to run the application in an in-memory SQLite3 database. First we install the SQLite3 project dependency like this.
Terminal:
npm install sqlite3 --save
Second we need to do a small adjustment to start script in package.json to setup the in-memory configuration.
/package.json
"scripts": {
"start": "cds run --in-memory"
}
Add Hierarchy Data Model
The data model needs to added in the created folder db. We place a new file there called
data-model.cds with the following definitions.
/db/data-model.cds:
namespace test;
entity Node {
key nodeID: Integer;
hierarchyLevel: Integer;
parentNodeID: Integer;
description: String;
drillState: String;
}
The entity Node describes the simplest persistence to represent a hierarchical structure. Of course this definition can be adjusted to your needs with additional fields or different types, etc.
Filling the entity Node with sample data via CSV is the easiest way to populate the hierarchical structure. Of course CRUD operation can be used to modify the hierarchy Node anytime.
The sample data is placed in file db/data/test-Node.csv with the following basic content.
/db/data/test-Node.csv:
nodeID;hierarchyLevel;parentNodeID;drillState;description
1;0;null;"expanded";"1"
2;0;null;"expanded";"2"
3;0;null;"expanded";"3"
4;1;1;"leaf";"1.1"
5;1;1;"expanded";"1.2"
6;2;5;"leaf";"1.2.1"
7;2;5;"leaf";"1.2.2"
Expose Service
To have the entity Node consumable, we expose it via an CDS OData V4 service like this.
/srv/hierarchy-service.cds:
using test from '../db/data-model';
service HierarchyService {
@readonly entity Node as projection on test.Node;
}
Bootstrap custom Server with CDS OData V2 Adapter Proxy
As explained in the introduction, we cannot use the OData V4 service directly, but have to transform it via the CDS OData V2 Adapter Proxy to an OData V2 service, to be consumable for our hierarchical UI.
So we install the respective module via npm with the call.
Terminal:
npm install @sap/cds-odata-v2-adapter-proxy --save
Now we can use this module by implementing a custom /srv/server.js, that allows to bootstrap the CDS OData V2 Adapter Proxy to expose an OData V2 service.
/srv/server.js:
"use strict";
const cds = require("@sap/cds");
const proxy = require("@sap/cds-odata-v2-adapter-proxy");
cds.on("bootstrap", app => app.use(proxy()));
module.exports = cds.server;
Start Application
We are now ready to start our application and check the OData services calls.
Terminal:
npm start
We see in the console, that the server has been started and the url http://localhost:4004 can be opened in browser.
The Welcome Page is displayed giving access to the hierarchy services (OData V4 & OData V2):
Node: http://localhost:4004/hierarchy/Node
Node (V2): http://localhost:4004/v2/hierarchy/Node
When opening the service URLs we can see our sample Node data in the OData V4 and in the OData V2 representation.
Build UI App
Having the backing hierarchy service in place, we can move forward to the creation of the SAP Fiori elements V2 app.
To build a basic SAP Fiori elements V2 app we add a new directory hierarchy in the app folder. There we place the necessary standard files Component.js and manifest.json.
The component is based on a SAP Fiori elements V2 app component like this.
/app/hierarchy/webapp/Component.js:
sap.ui.define(["sap/suite/ui/generic/template/lib/AppComponent"], (AppComponent) =>
AppComponent.extend("hierarchy.Component", {
metadata: {
manifest: "json",
},
})
);
The manifest.json needs to be adjusted to register the OData V2 hierarchy service as data source like this.
/app/hierarchy/webapp/manifest.json:
"dataSources": {
"hierarchyService": {
"uri": "/v2/hierarchy",
"type": "OData"
}
}
Point the OData Default model to the data source hierarchyService.
/app/hierarchy/webapp/manifest.json:
"models": {
"": {
"dataSource": "hierarchyService",
"preload": true,
"settings": {
"useBatch": true,
"defaultBindingMode": "TwoWay",
"defaultCountMode": "Inline",
"refreshAfterChange": true,
"metadataUrlParams": {
"sap-value-list": "none"
}
}
}
}
Last adjustment of manifest.json is to add a ListReport component based on the entity Node. Important here to mention is to set the tableType of the component settings to TreeTable.
/app/hierarchy/webapp/manifest.json:
"pages": {
"ListReport|Node": {
"entitySet": "Node",
"component": {
"name": "sap.suite.ui.generic.template.ListReport",
"list": true,
"settings": {
"condensedTableLayout": true,
"smartVariantManagement": true,
"tableType": "TreeTable",
"enableTableFilterInPageVariant": true,
"dataLoadSettings": {
"loadDataOnAppLaunch": "always"
}
}
}
}
}
Then the newly created SAPUI5 application is registered in the sandbox FLP by added the following definition in section applications of sap-ushell-config.
/app/fiori-apps.html:
applications: {
"Hierarchy-display": {
title: "Hierarchy",
description: "Hierarchy App",
additionalInformation: "SAPUI5.Component=hierarchy",
applicationType: "URL",
url: "./hierarchy/webapp"
}
}
Add Hierarchy Annotations
We are almost done, but the most important step is still missing. We need to express which elements of the entity Node are used to build up the hierarchy. This is done by “sap:hierarchy” annotations in the $metadata definitions, expressing the following information:
- sap:hierarchy-node-for: Node identification
- sap:hierarchy-level-for: Level in hierarchy
- sap:hierarchy-parent-node-for: Parent node identification
- sap:hierarchy-drill-state-for: Hierarchy drill state to influence drill down and visualization
So the question is: How can we get those annotations into $metadata to be consumed by generic SAP Fiori elements List Report. An annotation containing a colon (“:”) is not allowed in CDS.
Luckily SAP Cloud Application Programming Model documentation says something about this as well in section sap: Annotations.
Normally the annotations are translated by CDS automatically in EDMX, but we can manually add “sap:” annotations, by replacing the colon (“:”) with a dot (“.”). CDS compiler has a special logic, that translates those annotations back to the OData V2 SAP extensions in OData metadata.
So we add the following annotations to our entity Node in file app/hierarchy/annotations.cds including some other UI annotations.
/app/hierarchy/annotations.cds:
using HierarchyService from '../../srv/hierarchy-service';
annotate HierarchyService.Node {
nodeID @sap.hierarchy.node.for;
hierarchyLevel @sap.hierarchy.level.for;
parentNodeID @sap.hierarchy.parent.node.for;
drillState @sap.hierarchy.drill.state.for;
}
annotate HierarchyService.Node with @(
UI: {
Identification: [
{ Value: description }
],
SelectionFields: [ description ],
LineItem: [
{ $Type: 'UI.DataField', Value: description, Label: 'Description' }
],
HeaderInfo: {
$Type: 'UI.HeaderInfoType',
TypeName: 'Node',
TypeNamePlural: 'Nodes',
Title: { Value: description },
Description: { Value: description }
}
}
);
In order to get the annotation.cds file loaded, we place an index.cds file in the app folder that establishes a reference.
/app/index.cds
using from './hierarchy/annotations';
If we check the $metadata after application start we see, that our needed hierarchy annotations are present.
/v2/hierarchy/$metadata:
Display Hierarchy UI Result
And that’s basically all, we can start the application again with command.
Terminal:
npm start
and open in a browser the Welcome Page at url http://localhost:4004.
Now we will see in addition to the hierarchy service a web application that can be opened via endpoint /fiori-apps.html.
When we click our created SAP Fiori elements application “Hierarchy”, we will get the following result.
Browser:
We see our sample data in a hierarchical Tree Table visualization can drill down the tree by expanding and collapsing the nodes.
Summary
We have seen, how we can display hierarchical data in a TreeTable control as part of the SAP Fiori elements ListReport floorpan only based on CDS annotations.
Where to Go From Here?
We only created a very basic application, displaying hierarchical data in a TreeTable via SAP Fiori elements V2. Of course this application an be enhanced with further UI topics like:
- Additional table columns
- CRUD operations on hierarchy
- Row Actions
- Detail pages
- etc.
Conclusion
Feel free to use it, like or dislike it and share your feedback or thoughts in a comment. In addition, check out another example app called BrowseGenres, displaying hierarchical data as part of the Bookshop examples. It can be found in directory fiori/app/genres of repository cloud-cap-samples (added with Commit).