Thursday, 13 December 2018

Applying a style to a line of a classic report

APEX is a powerful tool, but even powerful tools have their shortcomings. One of the functionalities I need regularly is the styling of (parts of) a row of a Classic report based on a value from the base query of the report.

In my example I have a summary line of averages. This line is generated by the base query of the report. I would like to indicate the summary line by using bold characters and a light grey background. The bold characters could be applied in the query but it would imply mixing data and styling and would result in less readable query. The background has to be applied on the td element that cannot be influenced using the declarative features.
So how can this be solved elegantly?

The solution I chose is to include a hidden input element in the query that holds the name of a class to be applied to the tr element. The hidden element is appended to a column of the query for which escaping of special characters should be disabled.

select ename
    || apex_item.hidden(0,'summary-line','data-name="row_class" ') as ename
...

It is important to have the attribute data-name row_class. The value is the class name to be applied in the row. The first argument in the apex_item.hidden call is not important, unless it is a tabular form.

In the After Refresh Dynamic Action on the report, this class is applied to the row using this line of JavaScript code:

$('input[data-name="row_class"]').each(function() { $(this).closest('tr').addClass($(this).val());});

Now you can define whatever styling you want for the row. For the example I mentioned:

tr.summary-line td {
   font-weight: bold;
   background-color: #D0D0D0!important;   
}

Note that defining the background color does not work for tr elements, but should be applied on the td elements. Unfortunately the use of !important is needed because the alternate row coloring of APEX has very specific selectors, which would make our CSS very complex. 

It is also possible to style individual columns, for example showing the salary cell in bold red when the salary is too low:

select ...
     , sal 
    || case when sal < 1000
            then apex_item.hidden(0,'sal-to-low','data-name="row_class" ')   
       end         as sal
...

Combined with the following CSS it yields the desired result:

tr.sal-to-low td[headers="SAL"] {
   color: red;
   font-weight: bold;

}

The JavaScript supports multiple row_class items per row so you can apply multiple classes to a row. 

Happy APEXing