Tuesday, 18 February 2014

Splitting an Apex report into several columns

The other day I was asked to create a page where a large number of properties should be connected to an object. I created a report consisting of the rows with the property name and a check box. This resulted in a very long and narrow report. All of the data could not be seen without scrolling. So I decided the report should be split into a number of columns. And I wanted to avoid special constructs in Apex and SQL (I have done that before and it was very compex). So I decided to use JavaScript to move the rows. By using JavaScript the Apex transaction mechanism keeps functioning, Apex does not know or notice that anything in the layout of the page has been changed.

I want to achieve the right side situation starting with the left report ( that by the way continues a long way below where the picture ends)

With JavaScript a number of extra table elements are created on the same level as the table element containing the report. The thead element of the original table element will be copied to the other table nodes to provide the same heading and a tbody element will be created to house the rows. After that the rows can be distributed among the tables. With CSS the table elements are positioned next to each other. The only limit to the number of columns is the available horizontal space.
You should call the JavaScript function below at startup or in the refresh event when using partial page rendering.

function reportToColumns ( tabSelector, numCols )
{ var numRows = 0;
  // bereken aantal rijen per kolom
  var rowsPerCol = Math.ceil( ( $(tabSelector+' tr').length-1 )/numCols);
  var baseName = 'reportColumn'; 

  // maak kolommen aan
  for ( i = 2; i <= numCols; i++)
  { $(tabSelector).parent().append('
'); $(tabSelector+' thead').clone().appendTo( $('#'+baseName+i) ); $('#'+baseName+i).append(''); } // verdeel de rijen over de kolommen var id = 2; var dest = ''; $(tabSelector+' tr').each( function(index) { if (index > rowsPerCol) { dest = '#'+baseName+id+' tbody'; $(dest).append( $(this) ); numRows = numRows + 1; // wissel de kolom als rijen per kolom is bereikt if ( numRows >= rowsPerCol) { id = id + 1; numRows = 0; } } } ); }

I used classes for the layout of a specific report. You might need to change that according to your needs.
To make sure the div’s are placed next to each other a little bit of CSS is needed:
.reportColumn {
    display: block;
    float: left;
    margin-right: 30px;
    position: relative;

You can see this in action right here.
Note 03-10-2015: The software is dependent of the template used. The link above is suited for Theme 25. You will find a version for the Universal Theme here.

This method can be used on either Apex Reports or Apex Tabular Forms. In fact it is not a specific Apex solution and can be used on any HTML table. Happy Apexing