Show hierarchy on Fiori Elements Object Page - OData V4 with RAP
Previous 2 posts in this series dealt with showing hierarchy on a List Report page of a Fiori Elemetns application using Hierarchy capabilities of OData V4 with CDS Hierarchy. In this post, let's see how to show it on an Object Page.
All these objects are created and tested on BTP Trial account as of today when this post was first published i.e. on November 21, 2023. All ABAP source code used here are available in this Git Repo. Feel free to clone it using abapGit and use it for testing. All the objects created for this specific post are available in package ZDH_V4_HIER_OP.
Use Case
Suppose we have Order
which can have one or more Items
. An item may have a parent item. One parent item may have one or more child items. i.e. an item hierarchy. There is no restriction on how deep the hierarchy can go. We want to show this as a Tree Table (hierarchy) on the obejct page of Order
. This means, every time an object of an order is displayed, only those items which belong to that specific order should be shown. Also, while creating the hierarchy, items should be filtered based on the order number. This significantly reduces the processing required to construct a hierarchy. Because, we do not epxect an order to contain more than few hundred items or, may be, in rare cases, a couple of thousand items.
Data Model
We use a similar data model that we used in previous post. But, since I do not want to disturb the example objects created for that, I will recreate all objects that are required for this post in a different package - ZDH_V4_HIER_OP. For the purpose of brevitiy, I will not post source code of those CDS views here. You can find them and also clone them from the repo mentioned above. But, I will highlight important differences from the previous post, nevertheless. That's the whole point of this post.
In the end, the data model looks like this:
Notice these changes -
We created a different CDS view for hierarchy node ZDH_I_OrderItemNode_2
which has 2 associations now - one for hierarchy directory
filtering _OrderHeader
(which we will discuss later) and other for the parent-child relationship of item hierarchy _Parent
. Both these associations are promptly exposed from the CDS view.
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Hierarchy Node For Order Item'
@Metadata.ignorePropagatedAnnotations: true
...
define view entity ZDH_I_OrderItemNode_2
as select from ZDH_I_OrderItemBasic
// Directory Association
association [1..1] to ZDH_I_OrderBasic as _OrderHeader on _OrderHeader.OrderId = $projection.OrderId
// Hierarchy Association
association to ZDH_I_OrderItemNode_2 as _Parent on $projection.OrderId = _Parent.OrderId
and $projection.ParentItemNo = _Parent.ItemNo
{
key OrderId,
key ItemNo,
ParentItemNo,
...
_OrderHeader,
_Parent
}
CDS hierarchy ZDH_I_OrderItemHierarchyDir
has a directory
filter now using the association created above - _OrderHeader
. Notice that it also has a parameter p_order_id
which is used as filter criteria. Aall fields that are used for the on
condition of _OrderHeader
in the source CDS view should also be used in filter by
condition of hierarchy directory!
@EndUserText.label: 'Order Item Hierarchy'
@AccessControl.authorizationCheck: #NOT_REQUIRED
define hierarchy ZDH_I_OrderItemHierarchyDir
with parameters
p_order_id : ebeln
as parent child hierarchy(
source ZDH_I_OrderItemNode_2
child to parent association _Parent
directory _OrderHeader filter by
OrderId = $parameters.p_order_id
start where
ParentItemNo is initial
siblings order by
ItemNo
multiple parents not allowed
)
{
key OrderId,
key ItemNo,
ParentItemNo
}
Then, we create remainng RAP transactional processing and projection CDS views for Order Header and Order Item where Order Header is the root entity viz. ZDH_R_OrderHeaderDirTP
, ZDH_R_OrderItemDirTP
, ZDH_C_OrderHeaderDirTP
, ZDH_C_OrderItemDirTP
.
Create RAP BDEF for these in case you want to add actions to Order Item entity. But note that, as of now when this post was first written, it is not possible to add draft behavior or create, update, delete capabilities to Order Item which has hierarchy.
Link the CDS hierarchy we created earlier to projection CDS view entity ZDH_C_OrderItemDirTP
using annotation @OData.hierarchy.recursiveHierarchy
:
@EndUserText.label: 'Order Item Projection'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Search.searchable: true
@OData.hierarchy.recursiveHierarchy: [{entity.name: 'ZDH_I_OrderItemHierarchyDir'}]
define view entity ZDH_C_OrderItemDirTP
as projection on ZDH_R_OrderItemDirTP
{
@UI.selectionField: [{ position: 10 }]
key OrderId,
@UI.lineItem: [
{ position: 10, label: 'Item No' },
{ type: #FOR_ACTION, dataAction: 'SetToComplete', position: 10, label: 'Complete', invocationGrouping: #CHANGE_SET }
]
key ItemNo,
...
/* Associations */
_Header : redirected to parent ZDH_C_OrderHeaderDirTP,
_Parent : redirected to ZDH_C_OrderItemDirTP
}
Add required annotations to show some columns on list report and also to show some facets, especially, line item reference facet on header's object page. Refer to GitHub repo to see how #LINEITEM_REFERENCE
is added pointing to association _Item
in ZDH_C_OrderHeaderDirTP
.
Unlike before, this time we expose both OrderHeader
and OrderItem
entities in Service Definition ZDH_SD_ORDERITEM_HIER_OP
but not the CDS hierarchy iteself. Create a service binding with binding type "OData V4 - UI" and publish it. To my suprise, for some reason, in this case, "preview" from here does not show the item hierarchy out of the box like it did for list report page. So, to test it, we have to generate an app and make some changes to manifest.json
.
@EndUserText.label: 'Service Definition for Order with Hier on OP'
define service ZDH_SD_ORDERITEM_HIER_OP {
expose ZDH_C_OrderHeaderDirTP as OrderHeader;
expose ZDH_C_OrderItemDirTP as OrderItem;
}
Changes in Fiori Elements app
Head over to BAS (Business Application Studio) and generate a Fiori Elements List Report application. Choose OrderHeader
as main entity and OrderItem
as navigation entity. Once generated, find the file manifest.json
. If you followd the same naming convetion for entities that are exposed, then you will find an object named OrderHeaderObjectPage
in this file under sp.ui5 -> routing -> targets
. Add controlConfiguration
to the settings
object of this. It should look like this:
"OrderHeaderObjectPage": {
"type": "Component",
"id": "OrderHeaderObjectPage",
"name": "sap.fe.templates.ObjectPage",
"options": {
"settings": {
"controlConfiguration": {
"_Item/@com.sap.vocabularies.UI.v1.LineItem": {
"tableSettings": {
"type": "TreeTable",
"hierarchyQualifier": "ZDH_I_OrderItemHierarchyDir",
"selectionMode":"Multi"
}
}
},
...
}
}
},
Note that how a specific table is targetted by using the association name from OrderHeader
to OrderItem
i.e. **_Item**/@com.sap.vocabularies.UI.v1.LineItem
. This is because, an object page may contain more than one 'Line Item Reference` facets. For example, an Order may contain multiple partners, multiple contact persons and so on. So, we need to specify exactly which table/Line Item Reference facet whose settings we want to change.
Other notable changes are
we have changed the table type to Tree Table (default is Responsive Table)
we have targetted the CDS hierarchy
ZDH_I_OrderItemHierarchyDir
using propertyhierarchyQualifier
Test Data
I generated some orders with items/item hierarchies using this class (which was also used earlier but now adjusted to fill order header table with corresponding order numbers) - ZDH_HIERARCHY_FILL_DATA
. You may run this class in ADT or use somthing similar to generated test data, if some are already not there.
With this, if you run the Fiori app now, you should see the hierarchy as shown below on the obejct page of an order:
Expanded items would look like this:
Having worked with hierarchies on both OData V2 and OData V4, I can vouch that this is a great feat in terms of reducing development time required to develop such applications when it comes to OData V4. Also, there is a great deal of boiler plate code that was required in case of OData V2 developments - one had to create a CDS view with custom query implementation and write a lot of ABAP code in it to make things work. In OData V4, CDS Hierarchy is used internally without the need of any additional ABAP coding so that we can focus on real business logic
, as they always say!
More power to ABAPers, more power to you!
Cheers!