Tuesday, August 31, 2010

APEX Spring Cleaning

Each time you do a major upgrade APEX creates a new schema. It does not remove the older schemas, which allows you to roll back to previous versions in case something happens.

I was upgrading some older instances of APEX and realized that I still had some of these older schemas lying around and decide that it was time to do some spring cleaning (I realize that isn't exactly spring time, unless you live in Australia).

From the APEX installation guide (http://download.oracle.com/docs/cd/E17556_01/doc/install.40/e15513/otn_install.htm#CBHBABCC) here's how to identify and remove older versions of APEX.

Please read the documentation and understand what exactly you're doing before you do this!

- Identify old APEX schemas

SELECT username
FROM dba_users
WHERE (username LIKE 'FLOWS_%' OR USERNAME LIKE 'APEX_%')
AND USERNAME NOT IN (
SELECT 'FLOWS_FILES'
FROM DUAL
UNION
SELECT 'APEX_PUBLIC_USER' FROM DUAL
UNION
SELECT SCHEMA s
FROM dba_registry
WHERE comp_id = 'APEX')

- Remove old schemas
Connect as SYS using the SYSDBA role then run:

DROP USER FLOWS_030000 CASCADE; -- Where "FLOWS_030000" is the username from the previous query

Monday, August 30, 2010

JavaScript Console Logger

Note: This now has a new name, Console Wrapper, and has been moved to a Google project. Please go to http://www.talkapex.com/2011/01/console-wrapper-previously-js-logger.html for more information.

If you've been developing APEX applications for while, or any web applications for that matter, you'll eventually leverage the browser console. If you've used Firebug, then you've had the console accessible to you.

In case you're not sure what console is, it allows you to display debug information in a nice console window within your browsers. Most (i.e. all browsers but IE) are console enabled. The most common use of console is the console.log command:
console.log('hello world');

Console has a lot of great features. One drawback with it is that you have to remove calls to console before putting your code into production since not all browsers support console.

Removing instrumentation code before going into production can be annoying, especially if you need to debug it later on. To resolve this issue I've created a console wrapper. This allows you to leave your debugging calls in production code. Here are some features:

  • Works in all browsers. If run in IE nothing will happen, but no error message.

  • Allows you to set Levels. By default no messages will appear.

  • Support for jQuery chaining (see examples).

  • Will automatically set level to "log" if run in APEX and APEX is in Debug mode.

A copy of the console wrapper is available here: Download $logger_1.0.0.

The only change that you'll need to make is call $.console instead of console. The download file includes a HTML file with demos. I'd recommend looking at the .js file as well for inline documentation.

Here's an example along with its output:
$.console.setLevel('log');
$.console.log('Current Level', $.console.getLevel());
$.console.group('Available Levels');
$.each($.console.levels, function(i, val){
   $.console.log(i);
});
$.console.groupEnd();
$.console.log(($.console.isApexDebug()) ? 'In APEX debug mode' : 'Not in APEX debug mode');
$.console.group('Demo Chaining');
//Notice how you can write this out all in 1 line!
$('.red').log('Before Red').css({color:'red'}).log('After Red');
$.console.groupEnd();
$.console.info('Turning off console');
$.console.setLevel('off');


For more information about console please read the following articles:

- Console APIs: http://getfirebug.com/wiki/index.php/Console_API
- Firebug console example: http://getfirebug.com/logging
- Console tutorial: http://www.tuttoaster.com/learning-javascript-and-dom-with-console/

Friday, August 20, 2010

APEX Plugin: Simple Modal

I just published another plugin called Simple Modal: http://www.apex-plugin.com/oracle-apex-plugins/dynamic-action-plugin/simple-modal.html

This plugin allows you to use any region(s) (or DOM object) in your APEX application as a modal window.

When developing this plugin I learned a few more things that may be useful when developing plugins:

- Scope Creep: When developing a plugin you can make it do a lot of things. This may lead you to try and include extra unnecessary functionality. Try to remember the goal you're trying to achieve, or more importantly, what you're developers will try to achieve with the plugin.

- Instrumentation: I'm a big fan of Tom Kyte and really like the emphasis he puts on Code Instrumentation. You may want to add some debug information in your JavaScript code to help you understand what is going on. As part of this plugin I included a logger package which is essentially a wrapper for console but will work in all browsers. I'll write about this in another post and include the final copy for general use.

Wednesday, August 18, 2010

APEX 4.0 Interactive Reports - Customize Wait Display

Over a year ago I wrote about how to customize the APEX IR wait logo (http://www.talkapex.com/2009/04/apex-interactive-reports-customize-wait_28.html). If you read that post you'll notice it's quite lengthy and can be intimidating if you're new to JavaScript.

With APEX 4.0 this is a lot easier to do since they're plugins to declaratively add this functionality. This post will go over how to customize the APEX IR Wait logo in APEX 4.0. You can try a demo here: http://apex.oracle.com/pls/apex/f?p=20195:3200

- Create an IR report region

SELECT e.*, SUM (e.sal) OVER () test
FROM emp e
CONNECT BY LEVEL <= 5

- Install Plugin

- Download the Simple Modal plugin: http://www.apex-plugin.com/oracle-apex-plugins/dynamic-action-plugin/simple-modal.html
- Shared Components / Plug-ins / Import
- They're 2 plugins included in the zip file. Import both of them (Show and Close)

- Create Show Dynamic Action

- RClick on the IR region and click "Create Dynamic Action:
- Advanced
- Name: Show IR Wait
- Next
- Event: Before Refresh
- Selection Type: DOM Object
- DOM Object: apexir_WORKSHEET_REGION
- Note: We're using the DOM object and not the region since we can port this example to Page 0 and it will apply to all your IRs
- Next
- Action: Select Simple Modal - Show
- You can modify some of the plugin attributes here if you'd like
- Next
- Selection Type: DOM Object
- DOM Object: apexir_LOADER
- Create

- Create Close Dynamic Action

- RClick on the IR region and click "Create Dynamic Action:
- Advanced
- Name: Close IR Wait
- Event: After Refresh
- Selection Type: DOM Object
- DOM Object: apexir_WORKSHEET_REGION
- Next
- Action: Select Simple Modal - Close
- Create

Now when you run the IR it'll make the screen modal while it's reloading the data. If you want to run on all IRs then you can add this dynamic action to Page 0.

If you run the demo in a console-enabled browser (Firefox, Chrome, Safari) you'll notice that the plugin includes some additional debug information. I'll be posting the logging JavaScript package that was used in the plugin soon.

APEX Plugin: Debug Mode and Console

When running an APEX application in debug mode, it will provide debug information in the console regarding any plugins that get executed. Note: Console is supported by most browsers

Here's an example of the output:

Tuesday, August 17, 2010

APEX Plugin: Javascript Attributes

Recently I was developing an APEX dynamic action plugin and ran into a bit of an issue. One of the custom attributes that I defined was a yes/no attribute which returned "true" or "false" respectively.

When I was testing my plugin it always behaved as though the user had selected yes/true even though they selected no/false. After some debugging I saw that the plugin values in Javascript were strings. Clearly strings are not booleans and they behave differently when evaluated.

To resolve this problem I just changed my if statement:

//From
if (this.action.attribute01)
//do something

//To
if (this.action.attribute01.toLowerCase() == 'true')
//do something

If you're new to JavaScript, here's how JavaScript handles strings when doing comparisons:

x = null;
console.log(x, x ? true : false);
x = '';
console.log(x, x ? true : false);
x = 'false';
console.log(x, x ? true : false);
x = 'true';
console.log(x, x ? true : false);

Here are the results:


As you can see a string returns true if it contains some data.