Wednesday, 22 December 2010

Modifying Apex Tab behaviour

Today I was having a minor battle with tabs in Oracle Apex (3.2).

Sometimes you don't necessarily want it to submit the page when you click on a tab, so I was having a think about options to override the functionality.

I found an interesting discussion here on OTN, but I came up with something else involving On Demand processes. I'm still deciding whether it's an overkill for my situation, but I thought I'd post it as it may help someone else one day.

The solution involved :
  1. Current tab page template
  2. Script on page zero
  3. On-demand page process
My original "Current Tab" in my page template looked like this:
<td class="t9tabCurrent">
<a href="#TAB_LINK#" class="t9tabCurrent">#TAB_LABEL#</a>
#TAB_INLINE_EDIT#
</td>
I modified it to:
<td class="t9tabCurrent">
<a href=javascript:tabNav("#TAB_LINK#") class="t9tabCurrent">#TAB_LABEL#</a>
#TAB_INLINE_EDIT#
</td>

This calls a script I defined on page zero, passing through the original #TAB_LINK# code.
<script language="JavaScript">
<!--
function tabNav(p_orig)
{
  var get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=tab_target',$v('pFlowStepId'));
    get.addParam('x01',p_orig);
    vReturn = get.get();
    window.location = vReturn;
}
-->
</script>
The script will catch any click on the tab set. It takes the #TAB_LINK# substitution value and sends it to the on-demand process for processing. Then it re-directs the page to the resulting vReturn value.

My on demand process just encapsulates the code, so it's a call to a package I have defined. The g_x01 variable is the value I added in the AJAX call :
htp.p(my_pkg.tab_target(apex_application.g_x01));
This function definition simply replicates existing behaviour, but without the page submit.

FUNCTION tab_target
  (p_source  VARCHAR2)
  RETURN VARCHAR2 IS
-- Replicate tab functionality, but not as a submit
  lc_target  VARCHAR2(200);
  lc_delim   VARCHAR2(1) := q'[']';
  ln_session NUMBER := nv('SESSION');
  ln_app_id  NUMBER := nv('APP_ID');
  lc_debug   VARCHAR2(5) := v('DEBUG');
BEGIN
  SELECT 'f?p='||ln_app_id||':'||tab_page||':'||ln_session_id||'::'||lc_debug||':' -- essentially existing behaviour
  INTO  lc_target
  FROM  apex_application_tabs
  WHERE application_id = ln_app_id
  AND   tab_name = SUBSTR(p_source -- obtains T_HOME from -- javascript:doSubmit('T_HOME')
                         ,INSTR(p_source,lc_delim)+1
                         ,INSTR(p_source,lc_delim,1,2)-1-INSTR(p_source,lc_delim));

  RETURN lc_target;
END tab_target;
You could extend this to do whatever you like, depending on which tab has been pressed. I know in the past I've considered wanting to pass parameters on tab press...

Hopefully all the code is displayed ok, I'm having trouble finding an easy way to paste html examples into blogspot. I'm happy for any suggestions on that matter...

So, is anyone still working or reading blogs right now, or am I one of few? ;-)

8 comments:

Scott Wesley said...

Sorry about the double post - I really must start using a working draft title so I don't accidentally post without one!

Mn Twins Tickets said...

I was wondering if you ever considered changing the layout of your blog? Its very well written; I love what youve got to say. But maybe you could a little more in the way of content so people could connect with it better. Youve got an awful lot of text for only having one or two images. Maybe you could space it out better?

JC Lin said...

The information is very helpful to me. One reminder, the Menu Name should be unique and without space.

Scott Wesley said...

Thanks for the input, JC.

I thought I responded to Mn Twins Tickets - yes, I have since that comment, and will again - but possibly not for the reason of too much text, not enough images.

Scott Wesley said...

I've also spotted some performance issues I've learnt since this post, I better update it!

Salman said...

I cannot begin to thank you enough for this post. It probably just saved my skin for tomorrows presentation. Just noticed the huge amount of data being submitted when clicking on tabs from my application page. Your solution is a fix to a lot of my worries. Hats off for you.

Scott Wesley said...

Glad to hear I helped. This post probably needs a little updating, such as removing v('') from the SQL. There are also a few other solutions out there using Lists instead.

Simsteve7 said...

Helped me a lot.
I edited the href from the template, like this it also works for tabnames containing spaces.
"javascript:tabNav("#TAB_LINK#")"