Thursday, October 13, 2016

OTN Nordic ACE Tour : A Tale of Three Cities

3 days - 3 cities - 6 presentations (4 different ones)

My tour started on Monday afternoon when I left my house around 1.30PM to get on the bus to the train station. The 2PM train left exactly on time for the Amsterdam airport. I arrived at Schiphol around 3:30PM, perfectly on time to catch the 5PM flight to Copenhagen.
The flight to Copenhagen was very uneventful. From the airport I took the train / metro into the city. I already received an email message from one of my co-travellers, Martin Widlake, who was sitting al alone in a bar downtown. The poor guy. So I rescued him and was briefly after that joined by Sten Vesterli - another ACE Director from the organising country. After just one beer we head over to the restaurant where we met the rest of the board of the Danish Oracle User Group and the other two co-travellers, John King and Ludovico Caldera, for a very nice dinner.
As the city was crowded due to another - slightly larger - conference all hotel rooms were either booked or extremely expensive or far far away, the speakers were invited to stay the night at one of the board member's houses. I had the honour to stay at Sten's place and had a good night sleep.

The next morning we had a short drive to the Oracle office were breakfast was served and about 70 attendees showed up for the sessions. My two sessions - about JavaScript and APEX 5.1 - were well attended and went smooth (in my opinion). The lunch was excellent and the Miracle beer during the afternoon "coffee" break was very welcome. When the last speaker was done we went straight to the airport for our flight to Oslo. We killed the time by talking and drinking just one beer.
In Oslo we took the high speed train into town, walked a few 100 metres to our hotel and were welcomed by Øyvind. After dropping off our bags we quickly went to something called the "Beer Palace" at a very short distance of the hotel. But before we enjoyed the local drinks we went to the burger joint next door to grab a bite (we took it back into the bar to be exact). Not much later Ann-Sofie (another OUGN Board member) joined us as well. And after a drink or two we called it a night.

The venue in Oslo was very close by, so after an excellent breakfast we walked down there in just 5 minutes. I estimate about 50 attendees here. All 4 presenters had to deliver 3 presentations each - so at the end of the day we were quite "done". We declined the invitation to "have just one beer" (sorry Bjørn) and went to the train station and straight to the airport. While waiting for our next flight to Helsinki we grabbed a beer and a sandwich.
The flight to Helsinki took just over an hour, but included a time zone shift. When we arrived at the airport we took a shared cab that brought us to our hotel downtown were we arrived around 10:30PM. And the bar would close at 11PM. So a quick check-in, drop off the bags and use the remaining bar time properly.

For the next morning Heli had invited us for a tour through downtown Helsinki. So after breakfast we walked around enjoying the cool air (just above freezing) of Finland! This is were the local "Glögi" was more than welcome!
After returning safely back to the hotel, grabbed our stuff, checked out and walked 30 meteres to the Accenture office where the OUGF event was held. The event started with an excellent lunch, after which myself and Martin did our talks. And there is where our paths split. While Martin and I left for the airport to catch our 6PM'ish flights back home, John and Ludo stil had to do their presentations and will later catch their flights to the last stop, Stockholm.

As this was my very first ACED tour, I have to say it was quite an experience. It feels like: get into a taxi, onto a plane, into a train, find the hotel, do a presentation and then start this sequence all over again. So busy, very busy, But with the good company of Martin, John and Ludo it actually quite enjoyable!
Thanks to the local user groups for inviting me and thanks for the OTN ACE Program for the support! It was a blast.
(now in the lounge waiting for my flight back home....)

Monday, October 03, 2016

APEX 5.1 NF : Show Custom Application Icons in the APEX Builder

It just isn't fair. If you install a Packaged Application - and you should because there is a lot to learn from those apps - in your APEX Workspace they all have a cool looking icon. And your own applications, just show up with two characters in a (random?) coloured box. Why can't I have a nice looking icon for my application?

In APEX 5.1 you can!
Upload an image as a Static Application File. According to the help it should by 64 x 64 pixels, but I noticed it can be larger as well. It should be square though to show up nicely. Don't put it in a (sub)directory, it should be placed in the 'root' folder.

Then edit the Application Definition (either via Shared Components > Application Definition Attributes or by clicking on the "Edit Application Attributes" on the Application Builder home screen. Then scroll down until you see the "Icon File Name" property. Enter the name of the uploaded file there - but don't reference #APP_IMAGES# as you're used to! 

Now switch back to the APEX App Builder Home screen ... and your application is there with your custom application icon!

So in 5.1 there's no difference anymore in the presentation of Packaged Applications or your own... they can all look good!

It's happening again ... running for the ODTUG Board of Directors 😉

For the third time in a row I'll be running for ODTUG's Board of Directors. But after ending as a runner up twice, I am sure I'm going to make it this time! But not without your help!

My campaign statement this year is:

I have been attending and presenting at Kscope conferences since 2007. This not only resulted in a vast amount of knowledge, but also - and even more important - a huge number of friends from all over the globe.  I want to see ODTUG grow and spread this community feeling even more! 

My experience as an attendee, presenter and content lead has provided the basic foundation to be a director. Next to that, my personality and (global) network will be beneficial to the whole board and organization. 

Since March I have served on the Board of Directors in a limited term for a Director who stepped down due to a career change. This has allowed me to have unique insight of all the things that are going on in and around the ODTUG organization. As the train was already rolling full steam ahead, I tried to lend a helping hand wherever I could. 

Now, I seek your support as a full term elected member of the board so that I may become even more involved by heading a standing committee and serving a full two year term.  I am really looking forward to making a difference and helping the organization continue to move forward. I feel as if these last six months were a sort of internship that can give me a jump start for the next term! 

So don’t hesitate and vote for Roel! 

See for more details. You can even sign up as a supporter!
But even more important ... if you are eligible to vote: Please do so! 
You can vote from October 4 to 25.

Thursday, September 29, 2016

OTN Nordic ACE Tour

In 1.5 week I'll be travelling to and through the Nordics as one of the speakers during the OTN Nordic ACE Tour. It will be quite a busy schedule!

On Monday afternoon I'll be flying to Copenhagen and will meet my fellow travellers for the week during a dinner hosted by the Danish Oracle User Group. On Tuesday I have two sessions during the event: One about APEX JavaScript API's and one about APEX 5.1.  At the end of the day it's off to the airport to catch the flight to Oslo around 7PM. I foresee an airport dinner here....

Wednesday in Oslo I have even three sessions: About the Universal Theme, APEX 5.1 again and APEX and JET.  At the end of the day it's off to the airport again to catch the flight to Helsinki around 7PM. Probably another airport dinner here ....

Thursday morning Heli will take us for a short (but brisk) walk through Helsinki, before the Finnish event starts around noon. Here I have only one session, about APEX 5.1 again. And again ... back to the airport to catch the flight back to Amsterdam around 7PM. Airport dinner anyone?

So it'll be a very busy few days, but fun as well!
And of course thanks to OTN for supporting this trip.

Tuesday, August 30, 2016

Fix Interactive Report headers issue when using a Region Display Selector

When you have multiple Interactive Reports (IR) on your page and use a Region Display Selector to mimic tabs, you might notice some weird behaviour in the IR headings if you switch tabs. The headings are not positioned correctly and you get an extra empty row under the headings. It just looks weird and ugly. But if you resize your browser window, it all looks fine again (until you switch to another tab..)

So can we fix this by creating a Dynamic Action that mimics that "browser window resize" event?
Yes we can!

Create a Dynamic Action that fires on Click of the jQuery selector li.apex-rds-item a. That should fire a JavaScript snippet : 
apex.event.trigger(this.triggeringElement, "apexwindowresized");

So now a click on a tab not only switches from one IR to another but also fires that event that will "autofix" the IR headers. A simple solution for an annoying problem.

This applies to APEX 5.0, I assume it will be solved in 5.1.

Thursday, August 25, 2016

Creating an APEX plugin for an Oracle JET component - Part 2

In my previous blogpost I showed how you can embed an Oracle JET component in your APEX application. Now it is time to make a plugin out of the wisdom we gained doing so.
First of all a disclaimer. My intention is to make this plugin and the inner workings as simple as possible. So you can add a lot more functionality, checks etc and therefore add complexity. But this is intended to be as simple as possible.

The plugin consists of three parts: a PL/SQL render function, a snippet of JavaScript and a PL/SQL ajax function.

The render function is defined as :

function render 
( p_region                in  apex_plugin.t_region
, p_plugin                in  apex_plugin.t_plugin
, p_is_printer_friendly   in  boolean 
) return apex_plugin.t_region_render_result 

  c_region_static_id      constant varchar2(255)  := apex_escape.html_attribute( p_region.static_id );

  -- Add placeholder div
  sys.htp.p (
     '<div class="a-JET-PictoChart" id="' || c_region_static_id || '_region">' ||
       '<div class="a-JET-PictoChart-container" id="' || c_region_static_id || '_chart"></div>' ||
     '</div>' );
  -- Load the JavaScript library   
  ( p_name      => 'pictoChart'
  , p_directory => p_plugin.file_prefix
  -- Initialize the chart
  ( p_code => 'jet.picto.init('||
                  '"#'||c_region_static_id||'_chart", '          || -- pRegionId
                  '"' || apex_plugin.get_ajax_identifier ||'"'   || -- pApexAjaxIdentifier
  return null;
end render;

So what it does in these three steps is :
1. Generate a DIV placeholder, just as we saw in that previous post
2. Load the JavaScript file "pictoChart.js",
3. Execute the JavaScript function "jet.picto.init" providing two parameters, the regionId of the DIV and the (internal) identifier of the PL/SQL ajax function.

The contents of the JavaScript file is :

! function (jet, $, server, util, debug) {
    "use strict";
        baseUrl: apex_img_dir + "oraclejet/js/libs",
        paths: {
            "jquery": "jquery/jquery-2.1.3.min",
            "jqueryui-amd": "jquery/jqueryui-amd-1.11.4.min",
            "ojs": "oj/v2.0.0/min",
            "ojL10n": "oj/v2.0.0/ojL10n",
            "ojtranslations": "oj/v2.0.0/resources",
            "promise": "es6-promise/promise-1.0.0.min"
        shim: {
            jquery: {
                exports: ["jQuery", "$"]
    }), jet.picto = {
        init: function (pRegionId, pApexAjaxIdentifier) {
            require(["ojs/ojcore", "jquery", "ojs/ojpictochart"], function (oj, $) {
                server.plugin(pApexAjaxIdentifier, {}, {
                    success: function (pData) {
}(window.jet = window.jet || {}, apex.jQuery, apex.server, apex.util, apex.debug);
// To keep ThemeRoller working properly:
define("jquery", [], function () {
    return apex.jQuery

The first function call (requirejs.config) is again the same is we did earlier. Please note that the paths mentioned in here might differ in your environment. You could define those paths as (Application level) Component Settings, but for simplicity I keep them hardcoded in this example.
Notice there is a "jet" namespace defined and within that namespace a nested "picto" namespace. So we could easily extend this file (after renaming it) to other chart types. The "init" method defines the required files and then calls apex.server.plugin passing the PL/SQL ajax function as a parameter. After this ajax function is called, the result - a JSON object - is passed to the ojPictoChart function.
On the last line, as Kyle Hu correctly commented in my previous post, we have to define jquery in order to make ThemeRoller work (again).
So in fact, the JavaScript is very straightforward: in the end just an ajax call passing the result into the ojPictoChart function.

So what is the magic of the last piece, the ajax PL/SQL function? Here it is::

function ajax
( p_region    in  apex_plugin.t_region
, p_plugin    in  apex_plugin.t_plugin 
) return apex_plugin.t_region_ajax_result
  c       sys_refcursor;
  l_query varchar2(32767);
  l_query := p_region.source;
  open c for l_query;
  apex_json.write('items', c);

  -- add settings
  apex_json.write('animationOnDisplay' , p_region.attribute_01);
  apex_json.write('columnCount'        , p_region.attribute_02);
  apex_json.write('layout'             , p_region.attribute_03);

  return null;
end ajax;

Thus it just takes the region source - a SQL statement -, executes it returning a JSON object. And to these results three of the available options, defined as plugin attributes, are added. Again, as simple as possible. So no validation on the correctness of the SQL (as all APEX Developers can write a correct SQL statement, right). And just a minor part of the available options are exposed in the plugin.

When you create a region based on this plugin you have to provide it with a correct SQL statement - one that will return a valid JSON object according to the pictoChart docs. For example:

select ename||' - '||job||'@'||dname "name"
,      'human' "shape"
,      1 "count"
,      case job
       when 'PRESIDENT' then 'black'
       when 'ANALYST'   then 'blue'
       when 'CLERK'     then 'green'
       when 'MANAGER'   then 'red'
       when 'SALESMAN'  then 'yellow'
       end "color"
from   emp
       join dept on emp.deptno = dept.deptno
order by 2 desc, 4

And if you set the settings as :

You'll get as a beautiful result:
So knowing this, it wouldn't be hard to rebuild the plugin by yourself. But for the lazy readers out there, you can download it here too.
Or probably build another plugin for another JET component!

Saturday, August 20, 2016

Creating an APEX plugin for an Oracle JET component - Part 1

In APEX 5.1 (still Early Adaptor 1 at this moment), Oracle JET - Javascript Extension Toolkit -  is included to facilitate charting.
The APEX Development Team recently mentioned that not only the Data Visualisations part of JET will be included in APEX 5.1, but the complete installation of JET. The whole package. That won't do the size of the downloadable install file any good, but more important is: what can we do with it?

A number of the Data Visualisations will be exposed in APEX for the declarative definition of charts as we are used to now using the Anycharts library. But there are more Data Visualisations - check the JET Cookbook for all examples - and other components that might be of interest for an APEX application. So how can we use these in our apps?

As an example, I would like to use the PictoChart component in my application.
Fist of all - as we don't have APEX 5.1 yet - we need to download the Oracle JET library and install the files on either your web server or upload all of them into the APEX Static Files. As there are a lot of files - and I mean, really a lot - I would recommend storing the files on your web server.

Next, if you follow the steps of the JET Cookbook, you'll notice that they all make heavy use of the Knockout Javascript library. Knockout is extremely powerful, but also rather complex for most APEX developers. And in an APEX environment we don't really need it. So can we use Oracle JET components without Knockout, as there is no example on the (official) JET pages?
But there is an un(der)documented feature, which is the "initializer" call of an Oracle JET component, click here to open that part of the documentation of the PictoChart component. That looks more familiar to us, as it is just an (old fashioned) Javascript call with a JSON object as a parameter! So how do we get that on an APEX Page?

First of all we need to include RequireJS into our application by referencing


in the "File URLs" property of our Page. Of course, the exact location is dependent on where you stored the JET library. Next we have to tell RequireJS where all the Oracle JET files are that we need to load. Therefore we call (in the "Execute when Page Loads" property of the page) :

        baseUrl: apex_img_dir + "oraclejet/js/libs",
        paths: {
            "jquery"         : "jquery/jquery-2.1.3.min",
            "jqueryui-amd"   : "jquery/jqueryui-amd-1.11.4.min",
            "ojs"            : "oj/v2.0.0/min",
            "ojL10n"         : "oj/v2.0.0/ojL10n",
            "ojtranslations" : "oj/v2.0.0/resources",
            "promise"        : "es6-promise/promise-1.0.0.min"
        shim: {
            jquery: {
                exports: ["jQuery", "$"]

Now, also in the "Execute when Page Loads" property of the page, we can call the initializer of the PictoChart component :

    require(['ojs/ojcore', 'jquery', 'ojs/ojpictochart'],
      function (oj, $) {
           {items: [
              { name  : 'Have  Sleep Problems'
              , shape : 'human'
              , count : 7
              , color : '#ed6647'
              { name  : 'Sleep Well'
              , shape : 'human'
              , count: 3
           , animationOnDisplay: 'zoom'
           , columnCount: 5          

and finally we need to define component with the id "pc1" above mentioned into where the PictoChart is rendered by creating a region serving static content:

<div  id="picto-container">
  <div id='pc1'style="vertical-align:middle; margin-right:15px">
  <div style="display:inline-block; vertical-align:middle; font-weight:bold">
    <span style="color:#333333; font-size:1.1em">7 out of 10 college students</span><br>
    <span style="color:#ed6647; font-size:1.3em">have sleep problems.</span>

As a result we will see the exact same PictoChart as shown above in our APEX Page.
In the next blog post I will show how to convert this hard-coded data into an easy-to-use APEX plugin.

So stay tuned !

Friday, August 12, 2016

Consuming a REST Web Service returning JSON in APEX

In APEX you can define a web service that returns XML as below - all declarative, just a few steps through a wizard.

Then generate a report on top of that web service - again just a few clicks through a wizard. The generated query looks like this:

select xtab."customerName"
     , xtab."customerId"
  from apex_collections c, 
          XMLTable('/Response/S_getCustomerListTableArray/S_getCustomerListArrayItem' passing xmltype001
            COLUMNS "customerName" PATH 'customerName'
                  , "customerId"   PATH 'customerId'
          ) xtab
 where c.collection_name = 'CUSTOMERLIST'

So the result of the web service is stored in an XMLTYPE column. And it's easy to spot where you're definitions for the Response XPath and Output Parameters are used.

But what if your web service returns JSON - as more and more web services will do so? If you switch the Output Format of the web service definition to JSON, the Response XPath property and the Output Parameters are not enterable. And if you generate a report on top of that web service, the resulting query is a - disappointing - 

select c.clob001
from apex_collections c
where c.collection_name = 'CUSTOMERLIST'

and your report will show a JSON dump. Not exactly what you're hoping for. And notice the result is stored in a CLOB.

But since 12c, the JSON support in the Oracle database has improved a lot and we can easily use that in our query. So if we rewrite our query to 

select cust.*
from   apex_collections
,      json_table(clob001, '$.Response.S_getCustomerListTableArray.S_getCustomerListArrayItem[*]'
       columns ( "customerName"   PATH '$.customerName'
               , "customerId"     PATH '$.customerId'
               )) cust
where collection_name = 'CUSTOMERLIST'

we will get the same result as the - old fashioned - XML one! And as you can see the code is very much alike and could be generated by APEX itself just like the XML version.

So I expect that in a future version this functionality will be added to the APEX builder - it shouldn't be that hard to implement! And maybe the apex_collections can have a real "JSON" column as well (in fact it would still be a CLOB with an "IS JSON" check).

The only prerequisite is, you have to run APEX on version 12c of the database. If you want to know more about JSON in the database, there is a serie of blog posts about this, starting here.