Tuesday 27 September 2016

Positioning items next to each other

In the Universal Theme in Apex 5 it seems easy to position items next to each other. Just set Start new row to N and the item stays in the same row. However these items are usually very far apart:


You are limited by the columns in the responsive layout.

It is possible to position the items much closer and have much control over their position. For this you need to call JavaScript function with the names of the two columns as parameter:

position_after('P3000_FROM','P3000_TO');

You can download the JavaScript code here.

You can place the JavaScript code in the Javascript > Function and Global Variable Declaration.
Then the function position_after can be called in the Execute when Page Loads section, for each item you want to position.



The JavaScript removes the col-x classes from the input container of the first item and the label and input container of the second item. This class determines the fixed width of the container. Without this class the container’s width is determined by the content, so it fits tightly around the input or the label.
After removing the classes the JavaScript positions the label and input containers of the second item behind the input container of the first item.

The result of applying this function looks much better:



You can decrease the width of the items and they still stay together.


And there is control over the spacing applying left and right margins no the second label container.

#P3000_TO_LABEL {
   margin-left: 20px;
   margin-right: 20px;
}

In the result you see a larger spacing around the label:


The downside of this approach is that the responsive behavior is not optimal. Developing just for desktop this is no problem.
But if you really want a perfect responsiveness on all screen sizes you should stick to the column model of UT.

Happy Apexing



Thursday 15 September 2016

Using nice icons for links

As many people I am used to use the link images that Apex proposes when creating Forms with reports. And I end up with a bit grey images like:

Well, we are all used to it, aren't we?
Now would not it be much nicer if it would look like this:


This fits much better into the Universal Theme.

It is possible and in fact very easy. If you look at the properties of the link column in the report you see:

You just change the Link Text to   and define the class report-icon:

.report-icon { font-size: 1.6em; }

And you are done.
NB You can by the way use any font-awesome icon you want by changing the fa-xxx class. 

And if you want to use these icons in all your reports, you can define them once as a subsitution variable in the application properties:



 ... and use them in all your reports:




Happy Apexing



Sunday 11 September 2016

Displaying large numbers in human readable form

While developing the dashboard for the Apex Dashboard Competition I found the challenge of presenting large numbers in a readable form. If you want to display the population of countries in a report there is China and India with more than 1 billion inhabitants and Tuvalu does not reach 10,000. With a straight forward report it would look like the left image. The application apply of thousands separator improves the readability, but there is still too much detail in the numbers to easily get the meaning. The right image, where the numbers are formatted using size prefixes is much more readable.


You can see this in a useful example in the Apex World Dashboard. Select a country and look at the ranking table.
In Oracle Apex you can implement such formatting in your query, using a PL/SQL function. This solution has several disadadvantages:
  • Column header sorting is impossible because the actual numbers are replace by a character representation
  • Calling a PL/SQL function in a query can degrade performance
  • the readability of your query gets less
The solution is to apply the formatting using JavaScript. This way the query is not affected and the formatting is done after the sorting.
The formatting is implemented in a After Refresh DA on the report in question:
format_numbers_in_table('#report_tablespaces .t-Report-report');
The function formats all the cells with numeric content.
The parameter to the function should be the selector to the HTML table containing the data to be formatted. In this case the UT Standard Region and Standard Report are used with a static ID tablespaces.

If the report contains a large number of columns or some columns should not be formatted the columns to be formatted can be limited by passing an array of column names as the second parameter:
format_numbers_in_table('#report_tablespaces .t-Report-report',['LAND_SURFACE','POPULATION']);
Only the mentioned columns will be formatted.

Store the JavaScript functions on the page or seperately in a file. You can download the code here: Happy Apexing

Displaying large numbers in human readable form

While developing the dashboard for the Apex Dashboard Competition I found the challenge of presenting large numbers in a readable form. If you want to display the population of countries in a report there is China and India with more than 1 billion inhabitants and Tuvalu does not reach 10,000. With a straight forward report it would look like the left image. The application apply of thousands separator improves the readability, but there is still too much detail in the numbers to easily get the meaning. The right image, where the numbers are formatted using size prefixes is much more readable.


You can see this in a useful example in the Apex World Dashboard. Select a country and look at the ranking table.
In Oracle Apex you can implement such formatting in your query, using a PL/SQL function. This solution has several disadadvantages:
  • Column header sorting is impossible because the actual numbers are replace by a character representation
  • Calling a PL/SQL function in a query can degrade performance
  • the readability of your query gets less
The solution is to apply the formatting using JavaScript. This way the query is not affected and the formatting is done after the sorting.
The formatting is implemented in a After Refresh DA on the report in question:
format_numbers_in_table('#report_tablespaces .t-Report-report');
The function formats all the cells with numeric content.
The parameter to the function should be the selector to the HTML table containing the data to be formatted. In this case the UT Standard Region and Standard Report are used with a static ID tablespaces.

If the report contains a large number of columns or some columns should not be formatted the columns to be formatted can be limited by passing an array of column names as the second parameter:
format_numbers_in_table('#report_tablespaces .t-Report-report',['LAND_SURFACE','POPULATION']);
Only the mentioned columns will be formatted.

Store the following JavaScript functions on the page or seperately in a file. You can also download the code here:
/******************************************************
 * Display numbers readable
 *
 **********************/
function display_number(number)
{
  var sizes = [ {"base":1000,"symbol":"K"}
               ,{"base":1000000,"symbol":"M"}
               ,{"base":1000000000,"symbol":"G"}
               ,{"base":1000000000000,"symbol":"T"}
              ];
  
  var display = number.toString();

  if ( !isNaN(number) ) 
  {
    for ( i in sizes )
    {
      if ( number > sizes[i].base ) 
      {
        num1 = number / sizes[i].base;
        if ( num1 < 10 ) { num2 = Math.round(num1*10)/10; }
        else { num2 = Math.round(num1); }
        display = num2 + sizes[i].symbol;
      }
    }
  }

  return(display);
}
    
    
/******************************************************
 * Display numbers readable in table
 *
 **********************/
function format_numbers_in_table( table_selector, column_list)
{
  var table       = $(table_selector)[0];

  for (var rownum = 1, row; row = table.rows[rownum]; rownum++) 
  {
    //iterate through rows
    //rows would be accessed using the "row" variable assigned in the for loop
    for (var colnum = 0, col; col = row.cells[colnum]; colnum++) 
    {
      //iterate through columns
      //columns would be accessed using the "col" variable assigned in the for loop

      // format columns
      if ( col.innerHTML.length > 0 && col.innerHTML != ' ' )
      { 
        // if column list has content only format columns for this list
        var header = col.headers;          
        if ( column_list == null || column_list.indexOf(header) >= 0 )
        {
            col.innerHTML = display_number(col.innerHTML);        
        }
      }
       
    }  
  }
}


Happy Apexing