Dynamic Tables in the SAP CRM Web UI
In a recent project I had the requirement to create a large number of custom fields for order items. These fields should be editable in an overview assignment block on the order header level(ie. copied over from the ever so common Excel file; don’t ask….). Moreover, the fields are bound to change in the future. Therefore, extending the order item using the Application Enhancement Tool (Application Enhancement Tool) wasn’t really an option. Instead I was looking for a possibility to dynamically add fields to an order item using only customizing. The simplified configuration for utilities contracts (Simplified Configuration) offers exactly this possibility. Using customizing, additional field can be added to the product configuration of order items dynamically. However, usually fields are only editable on the order item level. The SAP CRM standard offers no overview on the order header level.
In general such an overview on the header level will not be very useful. For example, adding a large number of field to the configuration might render such an overview virtually useless. However, it was the only piece missing for me to implement the above mentioned requirement. The solution I was trying to implement was to dynamically generate the overview on the header level from the product configuration. The following screen shot shows the implemented view. In this view all editable fields are created dynamically from the product configuration.
While there is some information available on SCN regarding dynamic tables in the CRM Web UI (e.g. Dynamic columns in a table view), it was quite tricky to implement my requirements.In this blog I will summarize what is necessary in order to implement a dynamic, editable overview table based on customizable table fields. Even if you are not using the simplified configuration, this approach might still be useful to create dynamic views.
Step 1: Dead End
When I first heard about the requirement mentioned above I thought this should be easy. All I’d have to do would be implement a simple CRM view. Put a <chtmlb:configTable> tag in the html file and implement a custom GET_TABLE_LINE_SAMPLE in the context class to read the customizing. Done. However, this approach proved to be a dead end. For whatever reason it is not possible to create a <chtmlb:configTable> just using a dynamically created structure. The CRM WebUI framework somewhere in its nitty gritty implementation details checks if the table structure is a DDIC structure or not. Unfortunately, I forgot to note down where exactly this happens so I can’t put a pointer here. Therefore I had to come up with a different approach.
Step 2: Halfway there
The next thing I did was to search trough SCN to see if i could find a solution there. Here I found the blog Dynamic columns in a table view by Arunkumar Balakrishnan that seemed to describe exactly what I needed. Instead of implementing the view using the <chtmlb:configTable> tag I would have to use the <thtmlb:cellerator> tag to implement the view. The rest should then be easy again. However, also with this approach I was only able to implement half of the requirements. Although I was quite easy to implement a table dynamically build for a customizing table, the table was always in display mode. I wasn’t able to set the edibility of the table fields.
Step 3: The Solution
After reading through some old BSP documentation I eventually was able to implement the requirement. The solution consist of a simple CRM WebUI component with three important parts
- The view htm file using the <thtmlb:cellerator> tag
- A table context node implementing the if_htmlb_tableview_iterator interface
- a helper class for reading the table fields from the customizing.
The HTM File
The htm file (cf. screenshot below or #10270496 – Pastie) only contains two tags. The <thtmlb:toolbar> tag for creating the toolbar and the <thtmlb:cellerator> tag for creating the table. The important part of the <thtmlb:cellerator> tag is that the property iterator is linked to the context node ProdConfigAttributes.
The Context Node
The ProdConfigAttributes contexts node is a “normal” table context node inheriting from class cl_bsp_wd_context_node_tv. Its implementation consists of three interesting parts. First, it overwrites the get_table_line_sample method (cf. screenshot or #10270502 – Pastie) to create the table line dynamically from the customizing. The code to implement this is pretty simple. The helper class config_struct_builder creates a component table which can be passed to the CL_ABAP_STRUCTDESCR=>CREATE method to create the structure.
Second, it implements the interface if_htmlb_tableview_iterator. From this interface only the method if_htmlb_tableview_iterator~get_column_definitions needs to be implemented (cf #10270511 – Pastie). This methods controls the rendering of the table fields. In particular it is used to control the editability of table fields.
Most of the code shown below is specific to the use case I implemented. For example, lines 69 to 74 are used to add certain table elements that should never be editable and that don’t depend on customizing. For example, fields like the item number or the product of the item are added here. The interesting part are lines 79 to 88. For all dynamic table files the column name is added to the column definition in line 81. After that, lines 83 to 87 control the editability of the table fields depending on the editability of the view controller.
Finally the set_s_struct method (#10270524 – Pastie) method is overwritten to ensure that the order items are updated with the data from the table whenever a server round trip is triggered. This code is again rather specific to the implemented use case. Basically what happens here is a mapping back from the table line and column (represented by the parameters index and component).
The Helper Class
The finally part missing is the helper class to build the component table based on customizing (#10270539 – Pastie). The interesting method in this class is the get_structure_components method. It adds some static components as well as the dynamic components from customizing to the component table. The method get_dynamic_components uses a data access class (line 47) to read the dynamic fields from customizing. The method uses cl_abap_elemdescr=>describe_by_name (line 51) to fill the component table based on the name of a data element.
As always, once you know how to do something it seems obvious and easy. I hope this blog helps anybody with the requirement to implement dynamic tables in the CRM WebUI.