Conditional formatting for Tables in WebUI
In comments to one of my blog posts I indicated that conditional formatting in tables was quite awaited feature for me. There are plenty of scenarios when we need to highlight or indicate or distinguish something in tables in WebUI. And previous tricks were quite difficult to implement.
Just take a look at these discussions:
I expected that standard implementation would finally take into account already existed P_STYLE and/or P_CLASS changing parameters from IF_HTMLB_TABLEVIEW_ITERATOR~RENDER_CELL_START method. But it does not. I’ve already described the issue with table iterator and those parameters in this message
And here is the good news. As mentioned in SAP User Interface Technologies – Road Map (page 25) “Conditional formatting for Tables” is already available. Partially I think… Now it’s much easier to format tables based on some conditions. But “formatting” here means only table cell coloring. I was really surprised because I (again) expected more flexibility in formatting like an option to set styles or CSS classes to cells or rows. Yes, setting background color covers most of the needs. But “coloring” is not “formatting”.
To be completely sure that there is nothing else in shortly upcoming SPs I raised OSS message and received the oficial answer:
As per development there’s no new development considered regarding “Conditional Formatting of the cellerator’s cells” at this current time and there is no further information concerning the topic.
So how to do conditional formatting? The note 1937399 – Conditional formatting of the table cells introduces this feature. Need to admit that this feature is available starting from SAP CRM 7.0 Ehp1. How-To Guide is attached to the note. With this note we get one more property for table cell. Property name is
if_bsp_wd_model_setter_getter=>fp_bgcolor (or simply ‘backgroundColor’). We need to return color name or RGB hexcode as a string (for example ‘pink’ or ‘#FFC0CB’).
So some GET_P method should simply look like:
METHOD get_p_<your_cell>. IF iv_property EQ if_bsp_wd_model_setter_getter=>fp_bgcolor AND <your_condition>. rv_value = 'pink'. " or '#FFC0CB' ENDIF. ENDMETHOD.
The result is:
Cool! But what about a row? Certainly we can go and define as many GET_P methods to return this property as many attributes we have. And implement new GET_P method for each and every new attribute we add in the future.
Here I would suggest another way.
- Define static attribute in your context node class which represents table of pairs ‘index; color’ for buffering.
- Redefine GET_P_T_TABLE method of your context node class (inherited from CL_BSP_WD_CONTEXT_NODE_TV class).
- Handle the backgroundColor property in this method passing all other properties to super-method.
- For each new index trigger your condition and store the result in the index-color table.
- Retrieve the color from the table if possible.
Here is a code example:
METHOD get_p_t_table. DATA: lr_current TYPE REF TO if_bol_bo_property_access. FIELD-SYMBOLS: <fs_color> TYPE zts_color. IF iv_property = if_bsp_wd_model_setter_getter=>fp_bgcolor. READ TABLE gt_colors ASSIGNING <fs_color> WITH KEY index = iv_index. IF <fs_color> IS NOT ASSIGNED. APPEND INITIAL LINE TO gt_colors ASSIGNING <fs_color>. <fs_color>-index = iv_index. lr_current = me->get_bo_by_index( iv_index = iv_index iv_change_focus = abap_false ). IF lr_current IS BOUND. * There are some logic and conditions * Here it's based on current line entity in zcl_util_misc=>get_color as an example <fs_color>-color = zcl_util_misc=>get_color( lr_current ). ENDIF. ENDIF. rv_value = <fs_color>-color. ELSE. CALL METHOD super->get_p_t_table EXPORTING component = component iv_index = iv_index iv_property = iv_property iv_display_mode = iv_display_mode RECEIVING rv_value = rv_value. ENDIF. ENDMETHOD.
Where types and attribute are defined as:
PRIVATE SECTION. TYPES: BEGIN OF zts_color, index TYPE i, color TYPE string, END OF zts_color . TYPES: ztt_color TYPE TABLE OF zts_color . DATA gt_colors TYPE ztt_color .
Also we have to clean up gt_colors somewhere after completing the output. Because otherwise there will be issues during next rendering. For example when sorting is applied to this UI table. I used method CLEAR_LAST_LINE in context node class which is also inherited from CL_BSP_WD_CONTEXT_NODE_TV. It’s called from handler of CL_BSP_WD_VIEW_CONTROLLER~OUTPUT_RENDERED event and satisfied my needs.
And here is the result:
Sure enough, it’s easier and much better than previous approaches. But still there is a lack of flexibility… Anyway it should cover most of requirements. At least I hope so.