Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
HorstSchaude
Product and Topic Expert
Product and Topic Expert

It seems that everybody understand hierarchies but it is sometimes difficult to handle them, be it

  • Defining them,
  • Building them or
  • Rearranging them,
  • Not to speak about the whole stuff in the UI.

This document want to shed some light on these tasks. :grin:

Let’s first spent some words on “What is a Hierarchy”

Hierarchy as a Tree in Graph Theory

We will focus here on those special hierarchies in which the vertices have one or zero parents and one or many children which in turn are called Tree.

Second no cycles are permitted. Therefore following the Parent relationship we will reach some vertex without a parent which we will call Root. If we follow the Children relationship to the vertices without children these are the Leaves.

All vertices which can be reached starting from the Root vertex via the Children relationship are belonging to the same Tree (= Hierarchy).

Defining a Tree Hierarchy in BODL

Of course the vertexes are the nodes and the relationships are the associations. :grin:

As the Children association has the multiplicity “to-many” we cannot use the normal Alternative Key based associations as these have the multiplicity “to-one”. Instead we had to use the addition “valuation”. As result we can only target nodes from the own Business Object.

There are two different ways to implement such a Tree Hierarchy:

  1. You can define the associations on the root node of the Business Object.
    This means that the target is also the root node, but of another Business Object instance.
    So the vertexes are different Business Object instances like the hierarchy defined by the Business Object InstallationPoint.
  2. You can define the associations on a sub-node of the Business Object.
    Here the Business Object itself represents the hierarchy as a whole and all the sub-nodes define the hierarchy like in the Business Object ProductCategoryHierarchy.

For the sake of convenience we will work with the second approach here.

So here's the BODL for the Tree hierarchy:

At the Root node of the Business Object we define some information about the root of Tree hierarchy like the association which can be used later as the entry point for traversing the hierarchy.

The node Vertex defines the hierarchy itself:

  • The own identifier of the Vertex node.
    Please note that we did not use this identifier as Alternative Key because in that case we cannot use this value in any other hierarchy. We would need to combine it with the identifier of the whole Tree hierarchy.
  • The identifier of the own parent node.
    This value will be empty for the Root vertex of the hierarchy
  • The element HasKidsIndicator is needed later in the UI to determine if the expand / collapse icon shall be displayed for this entry.
  • Of course the associations Parent and Children based on the relationship between the own parent identifier and the identifier of the target node realizes in the valuation clause.

Adding some ABSL Code to Ensure Consistency

We will add an AfterModify script to the Root node of the Business Object to ensure that the root vertex of the Tree hierarchy is existing

And we add also an AfterModify script to the Vertex node to ensure the correct setting of the own HasKidsIndicator which is needed after removing children and also of the parent indicator which in turn is needed after re-arranging of a sub part of the hierarchy.

Define the List as Hierarchy in the UI

First you define the list of the Vertex node instances via an AdvancedListPane, but you add the "HierarchicalExtension" to this list

Second you need to define the bindings for this special structure

This is the result if there are already some vertices maintained. You notice the triangles which tells you that this vertex has children and if the children are visible. Technically spoken: The vertex is collapsed or expanded.
The vertex has no children if there is only a square shown.

You should not show the technical fields like "HasKidsIndicator" or "ParentId", because this information is already shown via the graphics.

It may be useful not only to expand or collapse the current vertex by clicking on the triangle but to show or hide the complete hierarchy. This can be achieved by some EventHandlers with List operations, for example "ExpandAll".

Add a Vertex

Adding an vertex is best done via a modification structure in own pop-up and not inside the hierarchical list.

Please use a data operation before starting the modifications structure which sets the current node as the new parent.

Inside the modification structure let the user only chose the ID and the description of the new vertex

This will prevent such issues like more than one Root vertex.

Delete a Vertex

If you would simple delete the current row, then exact only this would happen. As consequence all children of the current row would lose their parent.

So you need to ensure that on the deletion of a vertex all children (and the children of the children and so on) are deleted too.

This can easily achieved with a small action:

So add the line

action DeleteChildren;

to your BO definition and add this ABSL coding:

Which will delete in a recursive call (depth-first approach) the children and finally the current vertex.

Reorganizing Hierarchical Structure

If you want to re-arrange the hierarchy some precautionary measures should be taken:

  • Never allow a new parent for the Root vertex
  • Ensure that no circles are created
  • Verify if the new parent really exists.
    Otherwise you would decouple the sub-hierarchy from the rest.

The best way to ensure the later topic is to allow the user to select the new parent from a dropdown listbox. Just define a second list in the data model VertexList which is also bound to the Vertex node

Create a "NewParentId" element which is typed as a Code and bind the code list to this new VertexList using the ID and the Name.

I've added an EventHandler to "OnValueChanged" which updates the ParentId of the current selected line and does a Refresh on the VertexHierarchy.

After entering the new parent ID the hierarchy refreshes itself and shows the vertex under the new parent.

Sadly, this worked for me only in HTML5.

Now you should be able to create and modify hierarchies.

That's all, folks.

Horst

53 Comments
j_hemminghaus
Explorer
0 Kudos
Hello,

thanks for this nice blog. It helped me a lot to create a hierarchical list by myself.

I now tried to implement the locate functionality as can be done in the standard customer hierarchy. However, it doesnt do anythink.

I tried a simple case where i predefined the id in the event, but still the customer in my case is not shown.

 

Regards,

Jacqueline
frank_scherie
Discoverer
0 Kudos

Hello Horst,

 

trying to implement the first steps I hit an SAP 500

 

Step 0: Created in Cloud Application Studio an empty Solution FS_CDEVTASKS-5190

Step 1: Created BO FS_5190_Hierarchy.bo

import AP.Common.GDT as apCommonGDT;

businessobject FS_5190_Hierarchy {

// Root node must not be specified, it is created implicitly
//
// Add elements here.
//
// To declare an element as alternative key, use the [AlternativeKey] annotation.
// Please note:
// - An alternative key of type UUID exists implicitly for each node, enabling the node
// to be used as an association target.
// - The QueryByElements query is created automatically for each node.
// - Code completion is available with CTRL + SPACE.

// attributes of the Tree hierarchy
[Label("Tree Identifier")]
element Id : ID;

[Label("Tree Name")]
element Name : LANGUAGEINDEPENDENT_LONG_Name;

// defining the root of the Tree hierarchy
element RootId : ID = "ROOT";

association RootOfHierarachy [0,1] to Vertex valuation ( Id == RootId );
// defining the hierarchy itself

node Vertex [0,n]
{
[Label("Vertex Id")]
element Id : ID;

[Label("Vertex Name")]
element Name : LANGUAGEINDEPENDENT_LONG_Name;

element HasKidsIndicator : Indicator = false;

element ParentId : ID;

association Children [0,n] to Vertex valuation ( ParentId == Id );
association Parent [0,1] to Vertex valuation ( Id == ParentId );
}


}

 

Step 2: Created Script FS_5190_Hierarchy-Root-Event-AfterModify.absl

/*
Add your SAP Business ByDesign scripting language implementation for:
Business Object: FS_5190_Hierarchy
Node: Root
Event: AfterModify

Note:
- To access the elements of the business object node,
use path expressions, for example, this.<element name>.
- To use code completion, press CTRL+J.
- This script file is mass-enabled, i.e. the keyword "this"
refers to a collection of node instances.
- The solution uses this script if:
- the value of any field in the node in which this script is contained is modified.
- the node itself is modified by another business object within the same solution.
*/

import ABSL;

foreach (var obj in this)
{
// ensure that the hierarchy has a ROOT vertex
if (!obj.RootOfHierarachy.IsSet())
{
var RootVertex : elementsof FS_5190_Hierarchy.Vertex;
RootVertex.Id = obj.RootId;
RootVertex.Name = obj.RootId;
obj.Vertex.Create(RootVertex);
}
}

 

Step 3: Created Script FS_5190_Hierarchy-Vertex-Event-AfterModify.absl

 

/*
Add your SAP Business ByDesign scripting language implementation for:
Business Object: FS_5190_Hierarchy
Node: Vertex
Event: AfterModify

Note:
- To access the elements of the business object node,
use path expressions, for example, this.<element name>.
- To use code completion, press CTRL+J.
- This script file is mass-enabled, i.e. the keyword "this"
refers to a collection of node instances.
- The solution uses this script if:
- the value of any field in the node in which this script is contained is modified.
- the node itself is modified by another business object within the same solution.
*/

import ABSL;

foreach (var obj in this)
{
// Set HasKidslndicator to true when Number of children of current objetc is greater zero !
obj.HasKidsIndicator = (obj.Children.Count() > 0);

// We need to adjust parent HasKidslndicator if our parent exists - i.e. we are not root !
obj.Parent.HasKidsIndicator = obj.Parent.IsSet();
}

 

Step 4: Create Screens with Option Screen Scenario with Navigation using ID = FS_5190_V2 including FS_5190_Hierarchy_OWL.OWL.uicomponent

Step 5: Edit with UI-Designer FS_5190_Hierarchy_OWL.OWL.uicomponent and adding in Tab DataModel for Root.DataList by using Context Menu Add Hierarchical Extension

Step 6: Edit with UI-Designer FS_5190_Hierarchy_OWL.OWL.uicomponent and Binding in Tab DataModel the Root.DataList.Hierarchical Extension.Childfield to

Namespace: http://refsystems.sap.com/YBNSRCJGY_
Select BOM Model: FS_5190_Hierarchy
FS_5190_Hierarchy.Vertex.HasKidsIndicator

 

Step 7: Edit with UI-Designer FS_5190_Hierarchy_OWL.OWL.uicomponent and Binding in Tab DataModel the Root.DataList.Hierarchical Extension.ChildAssociation to

Namespace: http://refsystems.sap.com/YBNSRCJGY_
Select BOM Model: FS_5190_Hierarchy
FS_5190_Hierarchy.Vertex.Children

Step 8: Edit with UI-Designer FS_5190_Hierarchy_OWL.OWL.uicomponent and Binding in Tab DataModelthe Root.DataList.Hierarchical Extension.ParentAssociation to

Namespace: http://refsystems.sap.com/YBNSRCJGY_
Select BOM Model: FS_5190_Hierarchy
FS_5190_Hierarchy.Vertex.Parent

 

Step 9: Add BAC-Element with Scoping

Step 10: In ByDesign adjust Business Configuration so that Solution is scoped

Step 11: In ByDesign chose Application and User Management | Business User and adjust for the User the Access Rights by [Edit] [Access Rights]  so that Workcenter so that

WoC ViewID YBNSRCJGY001_HIERARCHY_WCF.WCF |  WoC View Name : FS_5190_Hierarchy
WoC ViewID  YBNSRCJGY_FS_5190_V2_WCVIEW  |  WoC View Name : FS_5190_Hierarchy View

both enabled and [Save]

Step 11: Logout

Step 12: Login to ByD with User modified in Step 11

Stept 13: Open WoC FS_5190_Hierarchy | FS_5190_Hierarchy View

SAP 500 occurs

Details
ClassName

sap.b.controller.event.PostRequest

MethodName

post

Response

<HTML><HEAD>
<TITLE>500 SAP Internal Server Error</TITLE>
</HEAD><BODY>
<H1>500 SAP Internal Server Error</H1>
<HTML><HEAD><br><TITLE>500 SAP Internal Server Error</TITLE><br></HEAD><BODY><br><H1>500 SAP Internal Server Error</H1><br>

Analysis:

  • The error consists even if the to scripts created in Step 3 and 4 are empty
  • The error will not occur if the Binding done in Steps 7, 8 and 9 will be removed and OWL saved


  • Doing Analsyis we get $SAP$ABAP$RuntimeError.3.zip with an Error

    Info: Fehler beim Generieren des virtuellen GO: Keine Übereinstimmung von Assoziationsziel 'DATALIST' und Bindung​

    which is connected to Root.DataList from Step 5 to Step 8



Issue occurs with ByDesign 2308

kind regards,
Frank Scherie

HorstSchaude
Product and Topic Expert
Product and Topic Expert
0 Kudos
Hello Frank,

I am sorry, but I have left the PDI team several years ago and have no access to the studio anymore.

Sorry,
Horst