I have to say that I love APEX 4.0, plugins and dynamic actions make life a lot more simpler as we’re able to avoid getting bogged down in javascript or installing/configuring/modifying framework type code. That is unless you have decided to use Ext JS with APEX…. which is the position I find myself in.
We transform our APEX forms into Ext equivalent ones, either on the fly after the page has loaded or pre-built in the page header and slotted into viewport code. Now for the transformed elements on the page I was hoping we could still use APEX’s builtin dynamic actions (not dynamic action plugins) and mixing in jQuery. In theory I thought this may work given that we reuse the same DOM ID for our transformed Ext input items. I was sadly mistaken.
Did I want to miss out on what the inbuilt dynamic actions provides me from a development productivity point of view? No way!! So what to do……. Well there were two options that came to mind (taking into consideration that I don’t want to write a dynamic action plugin for a dynamic action that is available in the APEX IDE. I have the long term vision of transforming existing APEX pages into Ext equivalent ones with minimal changes)
- I could override the existing APEX dynamic actions javascript with an Ext equivalent version (this would take some time)
- Or I could simply generate my dynamic action code on the fly by using the data dictionary.
I chose the second option for now as it was the easier of the two, as I’m really time constrained at the moment, however the first option is the more strategic path which I intend to go down in the future. That aside, in the space of about 90 minutes I came up with the following solution for hide and show support on our Ext select lists/combos. I’ve only started with this one as it was my immediate requirement and it’s not exactly elegant, but it does work.
Here’s the working prototype code which you put into a PLSQL process that runs before “Page Footer”…
CREATE OR REPLACE PROCEDURE ext_hide_show_dynamic_action
AS
l_app_id VARCHAR2(100) := v('APP_ID');
l_page_id VARCHAR2(100) := v('APP_PAGE_ID');
l_function VARCHAR2(10);
l_opacity VARCHAR2(10);
l_duration VARCHAR2(10);
--
-- Internal procedure to print out our hide/show function, rather than copy and pasting
-- this into two almost identical calls in the main section
--
FUNCTION print_js_function
( p_in_affected_elements IN VARCHAR2
, p_in_function IN VARCHAR2
, p_in_duration IN VARCHAR2
, p_in_opacity IN VARCHAR2
) RETURN VARCHAR2
AS
BEGIN
--
-- We need to check for any icons e.g. date picker, spinner etc.
-- We need to also hide the label and any resizeable text elements
--
RETURN 'Ext.select("label[for='||p_in_affected_elements||'],fieldset[id*='||p_in_affected_elements||'],'||
'[id='||p_in_affected_elements||'],[id='||p_in_affected_elements||'] + img[class*=x-form-trigger]").'||p_in_function||
'({'||
'duration: '||p_in_duration||','||
'endOpacity: '||p_in_opacity||','||
'remove: false,'||
'useDisplay: true'||
'});';
END print_js_function;
BEGIN
sys.htp.p(wwv_flow_utilities.open_javascript);
sys.htp.p('Ext.onReady(function() {');
--
-- Lets loop through each of our dynamic actions (we are looking for hide operations)
--
FOR c IN
( SELECT da.when_element when_element
, CASE da.when_condition
WHEN 'equal to' THEN '=='
WHEN 'is null' THEN
--
-- We need to check for LOV null value settings
--
CASE pi.display_as
WHEN 'Select List' THEN '== "'||pi.lov_null_value||'"'
ELSE '== "undefined"'
END
ELSE NULL
END when_condition
, da.when_expression when_expression
, lower(act.action_name) action_name
, act.affected_elements affected_elements
, act.affected_elements_type affected_elements_type
--
-- We have to work out the hide/show action to perform as we may
-- want to show an item based on a value, or do the opposite and hide
-- the item. The event result dictates what to do,
-- i.e. the one with "True" set
--
, CASE act.dynamic_action_event_result
WHEN 'False' THEN
CASE action_code
WHEN 'NATIVE_HIDE' THEN 'NATIVE_SHOW'
ELSE 'NATIVE_HIDE'
END
ELSE act.action_code
END action_code
--
-- Ext has a different event for a combo, select is for list item
-- selection, whereas change is the field changes onblur
--
, CASE da.when_event_internal_name
WHEN 'change' THEN
CASE pi.display_as
WHEN 'Select List' THEN 'select'
ELSE 'change'
END
ElSE lower(act.action_name)
END when_event_internal_name
, rownum rn
FROM apex_application_page_da da
, apex_application_page_da_acts act
, apex_application_page_items pi
WHERE da.dynamic_action_id = act.dynamic_action_id
AND da.application_id = l_app_id
AND da.page_id = l_page_id
AND pi.item_name = da.when_element
AND pi.application_id = da.application_id
AND pi.page_id = da.page_id
AND act.execute_on_page_init = 'Yes'
AND lower(act.action_name) = 'hide'
/*
--
-- Lets make sure that the dynamic action condition and authorisations are met
--
AND extjs_utils.auth_condition_check
( da.condition_type
, da.condition_expression1
, da.condition_expression2
, da.authorization_scheme_id
) = 0
*/
) LOOP
--
-- We are going to build a standalone function so we can also call it on page load
--
sys.htp.p('Ext.app.dynAct'||c.when_element||c.rn|| ' = function() {'||
'if (Ext.getCmp("'||c.when_element||'").getValue()'||c.when_condition||c.when_expression||') {'||
--
-- Our dynamic action tells us whetehr to show or hide
-- if our condition is met
--
print_js_function
( p_in_affected_elements => c.affected_elements
, p_in_function => CASE c.action_code WHEN 'NATIVE_HIDE' THEN 'fadeOut' ELSE 'fadeIn' END
, p_in_duration => '.75'
, p_in_opacity => CASE c.action_code WHEN 'NATIVE_HIDE' THEN '0' ELSE '1' END
) ||
'} else {'||
--
-- We do the opposite action of the above Hide or Show
--
print_js_function
( p_in_affected_elements => c.affected_elements
, p_in_function => CASE c.action_code WHEN 'NATIVE_HIDE' THEN 'fadeIn' ELSE 'fadeOut' END
, p_in_duration => '.75'
, p_in_opacity => CASE c.action_code WHEN 'NATIVE_HIDE' THEN '1' ELSE '0' END
) ||
'}'||
'}'
);
--
-- Lets add our event handler
--
sys.htp.p('Ext.getCmp("'||c.when_element||'").on("'||c.when_event_internal_name||'", Ext.app.dynAct'||c.when_element||c.rn||');');
--
-- Lets run our function on Page Load, to worrk out what the display should be
--
sys.htp.p('Ext.app.dynAct'||c.when_element||c.rn||'();');
END LOOP;
sys.htp.p('});');
sys.htp.p(wwv_flow_utilities.close_javascript);
--
-- Exception Handling Routine
--
EXCEPTION
WHEN OTHERS
THEN
-- Put your excpetion handling code here
RAISE;
END ext_hide_show_dynamic_action;
/
Backing out the Ext JS functionality is easy, we simply change our region template (which is responsible for the Ext JS page item transforms) back to a standard apex template and disbale the above process and we still have the exact same functionality of a hide show item, just using the standard APEX features.
If you’re not happy with adding custom PLSQL to either page zero or your pages then maybe creating a new dynamic action plugin is for you. It’s great that we have several choices, it’s just up to you “the developer” to decide which method suits your style/direction.
The one thing I’ve failed to mention about building JSON meta data objects and printing out dynamic javascript, is that we use additional resources by querying the data dictionary all the time (over and above building traditional APEX apps). This of course has performance impact when you start to scale your application(s). The simple solution (if you’re headed down this path) is to cache the outputted objects into custom tables and store these either, session, user, or application based depending upon your application requirement with expiration/invalidation policies. It will be then as simple as doing a check for a cached item and reusing it if it exists rather than querying the data dictionary for every page load.
Finally if you’re looking at developing your first region plugin, then download the following plugin written by Doug Gualt from Sumneva and install it. As there’s not much documentation or anything really useful that out there that walks you through how to do it, so it’s easiest just to edit Doug’s plugin to see how it hangs together. I coded my first region plugin last night (sad I know) and used this as my way to learn. I had my first region plugin (based on the Ext.manual documentation) completed in under 2 hours, it saved me hours! Thanks Doug!
P.S. this is a great way to generate a logo in ascii text, which sits nicely in your plugin header code.









