Tuesday, October 27, 2015

Remove vertical borders from Universal Theme Interactive Reports

In Template Options of Classic Report region you can set property to see only horizontal borders (property Report Border):


What about Interactive Reports? There's simple way to do it. Just open Theme Roller add this two lines of CSS in Custom CSS property:


  .a-IRR-header{
    box-shadow:none
  }
  .a-IRR-table td{
    border-left:1px solid transparent
  }



*Tested on APEX 5.0.1.00.06.

Thursday, October 22, 2015

Explore the mysteries of APEX Builder

If you've ever wondered how some things are done in APEX builder there's a simple way to find out. There's only one prerequisite: you need to have access to SYS or APEX_* user.

How to do it? It's pretty simple - open your favorite IDE - SQL Developer and connect as SYS or APEX_* user. If you're connected as SYS in Connections tab go to Other Users > APEX_* > Application Express folder. If you're connected as APEX_* user just go directly to the Application Express folder.


After that you can right-click on application or page that you're interested and explore its components (items, regions, processes, validations...).

Thursday, October 1, 2015

Speed Up Your APEX apps with JSON and Mustache.js

A few days ago I've started to explore the solutions to generate (and parse) JSON objects from APEX 5. During this research I came to an interesting facts and features.

First of all I found some great blog posts from Dimitri Gielis:
and Dan McGhan:
where you can read almost everything that you'll ever need to know about APEX and JSON.

After that I've decided to try it by myself. So I've created a simple examples of generating JSON from same source (query from all_objects table) with the different methods:
  • Example 1 - using apex_util.json_from_sql (fun fact: not documented)
  • Example 2 - using apex_json package and refcursor
  • Example 3 - using apex_json manual (open_object, wite, close_object)
  • Example 4 - manually with implicit cursor
  • Example 5 - manually with bulk collect
  • Example 6 - using REST service
  • Example 7 - using PL/JSON package

Source in all example was:
1
2
3
4
5
6
SELECT rownum x  
     , owner a  
     , object_name b  
     , object_type c  
  FROM all_objects  
 WHERE rownum <= 500 

Why I was using short aliases in the query, like x, a,b,c? Because size of a JSON object with short aliases for 500 rows was 29.1 KB and without aliases 43.3 KB (for 7000+ rows with aliases 461.0 KB, without 681.5  KB).
Maybe JSON is not so readable in case of short keys (aliases), but for a big JSON object difference in size is significant.

Why only first 500 rows? Because when you generate JSON using REST service there is limit and you can fetch only 500 rows by one request.
Update: you can change this in ORDS configuration file (parameter jdbc.MaxRows). See ORDS documentation for details.

Another fun fact: by using apex_json package size of JSON object was 32.1 KB. In all other examples size was 29.1 KB. I suppose it's because of unnecessary blank lines/characters.

After that I've compared average speed to generate JSON object. The fastest way was to generate it manually in Example 5 (by concatenating strings and by using sys.htp.prn), but I would recommend to use apex_json package. There are many reasons why and I won't explain them now.

When I got my JSON back I wondered what can I do with it in APEX except manually parsing it in jQuery. So I've googled about client side data binding methods implemented in JavaScript and found out Mustache.js.
What is Mustache.js and why I've choose it? It's JavaScript templating engine it's lightweight (min version around 10KB) and simple and you must agree that the name and logo are great!


I won't go into details how to use it. You have everything very well documented here. Maybe I'll cover this in some future post.

So, what did I use it for? It's simple - for templating. :)
I've picked up classic report template from Universal Theme added up Mustache tokens and voilà - I had same report as if it's generated by classic report region but it seemed really fast. Then I thought I should compare execution time and size with classic report region.

I've opened up my Console Window and saw interesting stuff. The size of classic report response (after region refresh) was 122KB and it took about 380ms (in average) to get it (the fastest way with JSON was around 100ms). It was more than 3x slower than JSON generation and the size of object was more than 4x bigger. Isn't this amazing? Should APEX in some future release use JSON and some templating engine for similar stuff?

By then, you can use it in your apps immediately. There are numerus ways, so be creative (see Choose Template option in example)!

For more, visit my presentations at SOIUG 2015 and HROUG 2015 in two weeks.

I hope I'll have more time to write more posts about JSON and Mustache.js soon.

Once again, you can see demo here.

*I've tested execution time and JSON size locally on APEX 5.0.1.00.06 and Oracle XE 11.2.0.2.0

Wednesday, September 23, 2015

APEX 5: Sticky Regions

You know that in APEX 5 you can (for IR) define how you would like to display report headings

  • Fixed to Region
  • Fixed to Page
  • None

By using same API (not documented) you can make your regions "sticky".
First, you have to set Static Region ID (for example rgnSticky) of your sticky region.



After that add onload JS code:
$("#rgnSticky").stickyWidget({toggleWidth:true});


Check out demo here.

*Tested on APEX 5.0.1.00.06.


Wednesday, September 2, 2015

Using PL/SQL block as result set for RESTful services

Maybe I'll save some time to someone with this post... :)

So, if you're using RESTful Services and your source type is PL/SQL you should wrap your code with BEGIN and END keywords.
I'm not used to do this in APEX since in every place where you're writing PL/SQL code this is done implicitly and I was surprised that here I had to do it explicitly.


I've tested this with APEX 5.0.1.00.06.

Wednesday, July 29, 2015

APEX 5: fixed IR column width

Setting fixed width of columns in IR in APEX 5 is a little different than in older APEX version. Here's an simple example of setting fixed width of Hiredate column of Employees report.
First you have to set column static ID:

Then you have to add CSS to page (or static file):


If you have more than one report on the page you can prefix CSS with region static ID, for example:

#regionStaticId th#colHiredate, #regionStaticId td[headers=colHiredate]{width:100px}

Update:
Use min-width CSS property instead of width (it fixes problem if you have many columns in report)
#regionStaticId th#colHiredate, #regionStaticId td[headers=colHiredate]{min-width:100px}

You can check out demo here.

Monday, July 20, 2015

Tuesday, May 26, 2015

APEX 5: Add Spinner to Classic Reports Plugin

I've created a little APEX5 Dynamic Action plugin that adds spinner on dynamic refresh of classic report regions (like you have for Interactive Reports).

You can see info and download it here: https://goo.gl/84ITaV


Tuesday, May 12, 2015

Tabular Form Bug

I found bug in tabular forms created over tables that have columns with timestamp datatype (datepicker fields).
If you try to update any column value you'll get error message like this one:

Current version of data in database has changed since user initiated update process. current row version identifier = "CB89E9B0740B64051B6CA00FD81E58166C2288FA" application row version identifier = "3641B87EB52532E016A0D8377AA8F181A6E2FBCA" (Row 1)

I'm getting same error on APEX 4.2.5.00.08 and 5.0.0.00.31 (apex.oracle.com).

The bug was reported to APEX team and it will be fixed in future releases (5.1).

Quick fix for this is applying explicit format mask for timestamp datepicker columns.


Thanks to Robert and Valentino Orehoci for pointing this out and Marc Sewtz for quick fix.

Tuesday, May 5, 2015

APEX 5: Issues with configuration of Static Files (ORDS)

If you're getting this alert window when going to your APEX 5 login screen:


after upgrading from older versions of APEX you're probably missed this paragraph in installation documentation:
When using Oracle REST Data Services as your web listener, static files are served using RESTful service module built into Oracle Application Express. Therefore, you must configure RESTful Services in new installations and in upgrade installations when RESTful Services were not configured in a previous release.

To fix it don't forget to configure Oracle REST Data Services by executing this script @apex_rest_config.sql.


Thursday, April 9, 2015

APEX 5: Deprecated and Desupported Features and Changed Behavior

I've started to read APEX 5 BETA documentation (Beta Draft: 2015-01-16) Release Notes and I've found out two interesting chapters -  Deprecated and Desupported Features and Changed Behavior.

In chapter named Deprecated and Desupported Features you can find many interesting things about APEX 5 and what should you avoid to use in your future APEX 5 applications. 

Here are some things that caught my eye more than others:
  • Deprecated column types in Classic Report. Oracle recommends to use Tabular Forms or APEX_ITEM API for creating editable reports.
  • File Browse Item should use APEX_APPLICATION_TEMP_FILES table for select, update or delete operations instead of WWV_FLOW_FILES. Deletes are no longer necessary, as the file will automatically be purged after the request or when the session is purged.
  • If you used WWV_FLOW_FILES as a permanent store, the files should be copied into their own BLOB column(s) within a table within your schema.
  • In APEX 5.0 there is only one button type which can be positioned in a region or next to items. Finally, no more Item Buttons! :)
  • Dynamic actions based on DOM Objects have been deprecated. You should use jQuery Selector or JavaScript Expression instead.
  • Page computations and validations based on SQL expressions have been deprecated. You should use PL/SQL expressions or PL/SQL Function returning VARCHAR2 types
  • #PLUGIN_PREFIX# substitution string is not supported any more in plug-in files. You should use relative URLs instead.


Also, there's a nice chapter about Changed Behavior. Here are some nice bullets to remember:
  • Static files will be stored in central repository that is available for a specific application (Static Application Files) or for all applications within a workspace (Workspace Application Files)
  • Static application files uploaded to Shared Components are automatically included in an application export. No more recreating supporting object scripts. :)
  • In a future version of Oracle Application Express, the dictionary view APEX_WORKSPACE_FILES will no longer include CSS, image or static files uploaded in Shared Components. You should use the new views APEX_WORKSPACE_STATIC_FILES and APEX_APPLICATION_STATIC_FILES instead.
  • Because of internal changes to the views APEX_APPLICATION_FILES and WWV_FLOW_FILES, it is not possible anymore to lock rows with SELECT FOR UPDATE

Please check the whole documentation for details. Remember, for now this is only BETA documentation. 
Don't forget to check those chapters in full documentation before moving to APEX 5.


Saturday, April 4, 2015

APEX 5: jQuery Migration

If you like to write custom JS code in your APEX applications or to use lots of 3rd party plugins you should be aware of changes in jQuery and JS libraries in APEX 5.


APEX 5 (at least current version 5.0.0.00.28) uses jQuery 2.1.3 and if you plan to migrate from APEX 4.2 you should check for changes from jQuery version 1.7.1 which is included in APEX 4.2. There are some things that are deprecated and removed like .die() or .live() event handlers.

Here you can find things that are removed:

But APEX development team was one step ahead and they provided us with quick solution to include jQuery Migrate plugin that restores deprecated features and behaviors of jQuery.

You can turn it on under the User Interface Attributes Page, JavaScript tab. My advice is that you should clean up your code and not to use any deprecated code.

Note that, as you can read in jQuery documentation, jQuery 2.x has the same API as jQuery 1.x, but does not support Internet Explorer 6, 7, or 8. APEX development team also thought of that and they put conditional comment to handle this:

<!--[if lt IE 9]><script type="text/javascript" src="/i/libraries/jquery/1.11.2/jquery-1.11.2.min.js?v=5.0.0.00.28"></script><![endif]-->
<!--[if gte IE 9]><!--><script type="text/javascript" src="/i/libraries/jquery/2.1.3/jquery-2.1.3.min.js?v=5.0.0.00.28"></script><!--<![endif]-->

Also be aware that by default when you create new application in APEX 5 there is no more old non-namespaced APEX JavaScript functions in your application (as part of legacy.js). You can include them by turning on property Include Legacy Javascript in User Interface Attributes page, JavaScript tab.

Again, don't do that. Rather clean up your code!



Sunday, January 25, 2015

On Demand Process Bug

In my last post I wrote about security of on demand application processes. While I was testing this I've noticed a bug in APEX version 4.2.6.00.03 and APEX 5 EA2 (probably in some older versions too).

If you have on demand application process (without authorization scheme) and call it from public page (e.g. login page 101) you'll get additional unwanted data in response message.

For example, if you create public on demand application process like this that outputs some string like"OK":

and call it in some on load dynamic action on public page (like login page):

When you take a look at console window you'll see additional data with "OK" string:

If you are expecting that your message is returning something in JSON format you'll get an JS error on page.

I've reported a bug to APEX team and they've fix it for version 5.

Friday, January 23, 2015

Secure your On Demand processes

By default when you create On Demand application process there is no authorization scheme selected:


and that makes your On Demand processes very vulnerable and publicly available.

For example, if you create On Demand application process without authorization scheme named DUMMY that creates record in DEPT table:


it can easily be called from browser console window without being logged in into application (e.g. on login page 101) by executing this JS statement:
apex.server.process ("DUMMY" 
                    ,{x01: "IT",x02: "LOS ANGELES"}
                    ,{dataType:"text"}
                    );

Table before executed JS statement:
DEPTNODNAMELOC
10ACCOUNTINGNEW YORK
20RESEARCHDALLAS
30SALESCHICAGO
40OPERATIONSBOSTON

Table after executed JS statement:
DEPTNODNAMELOC
10ACCOUNTINGNEW YORK
20RESEARCHDALLAS
30SALESCHICAGO
40OPERATIONSBOSTON
50ITLOS ANGELES

If you change authorization scheme of your On Demand application process to Must Not Be Public User:

it will not be publicly available and unauthorized users will not be able to call it without logging in into application.

Environment: APEX 4.2.5.00.08 and Oracle XE 11.2.0.2.0 database.