All the APEX apps we build these days have are built with an EXT interface. Most APEX regions we define are mapped to an Ext.Panel or a variation of. As part of the integration we place the APEX region button section into an Ext toolbar as a Panel allows the definition of a top and bottom toolbar. Now the cool thing about Ext is that these toolbars don’t have to be buttons, they can be menu’s, radio items, text fields, combo’s, sliders, spinners etc.
Now the problem becomes how can we use an APEX button to display as a Slider for example? The short answer is, it requires a long answer
Now before I jump into the deep end and a detailed explanation, the point to note with our efforts is to always use a generic approach to integration. There’s no point having to hard code Ext config in too many places within the APEX IDE for each individual button. We like to centralize the maintenance of code changes. We achieve this by using templates, but sometimes a template is not enough. For this particular requirement of showing a slider in place of a button in a Panel’s top toolbar is one of these cases.
Do you use shortcuts? Me personally, not very often until now….. it’s one of those APEX features I’ve never really tried to fully work out how to use properly, even though I’ve been developing with APEX for over 4 years now. After a little investigation my eyes have been opened to the usefulness of shortcuts for a couple of main reasons:
- We can centralize the maintenance of them, like templates they can be subscribed to. This means that our master application which holds our theme can now also hold all our shortcuts and we can make one centralized change and push the changes out to all the subscribing applications.
- The creation and maintenance of them is handled by the APEX IDE, we don’t need to bolt on some additional custom maintenance screens for managing javascript template code. Either presented in runtime development mode or creating something similar to the APEX builder plugin. This speeds up our development.
- Because a shortcut is an APEX component we can query the APEX data dictionary, this means that we can easily build JSON metadata objects in the page header with these templates which will be used when transforming malformed JSON outputted by our APEX templates client side. This improves portability.
So how do we use shortcuts in our design? The design itself is a little complicated and is made up of a number of hacks ( I say hacks as it takes say 3 or 4 steps to do something that normally takes one step). It goes like this.
We have a button template which looks like this:
{
"xtype": "slider",
"listeners": {
"change": {
"fn": function (slider, newval, oldval) {
var that = this;
if (that.fnTimeout) clearTimeout(that.fnTimeout);
that.fnTimeout = setTimeout(function () {
var val = newval;
#LINK#
}, 1000);
}
}
}#BUTTON_ATTRIBUTES#
}
This template design using the #LINK# substitution string allows to add custom javascript on a button by button basis to execute when the slider changes. We can manage the slider config by using the #BUTTON_ATTRIBUTES# field in the APEX IDE . Now this is fine, but the maintenance of having custom Ext config under #BUTTON_ATTRIBUTES# can become quite a headache, especially if we want to define a local data store or a significant amount of config. The text field in the APEX IDE is quite small so we find ourselves copying this to an editor and reading it/debugging it there. Normally most of these settings can be reused across multiple items, so in order to centralize the definition of this additional Ext config we use shortcuts. e.g. “EXT_BUTTON_SLIDER” is a shortcut which we’ve created in APEX…
Now I bet your probably wondering (if I haven’t lost you already) how we could possibly use a shortcut in the #BUTTON_ATTRIBUTES# field as they are only supported in the following:
The Region Source attribute of regions defined as HTML Text (with shortcuts).
Region Header and Footer Text attribute.
Item Label attributes and Default Value attribute.
Region Templates attributes.
The answer is at page generation time. We build a JSON metadata object in our page header by querying the APEX data dictionary which lists all our Ext button shortcuts, these shortcuts are snippets of Ext config which we’ll replace when building our toolbar. We use the name of the shortcut in the #BUTTON_ATTRIBUTES# section.
<script>
const extShortcuts = {
"EXT_BUTTON_COMBO": ",typeAhead: true,triggerAction: 'all',mode: 'local',store: new Ext.data.JsonStore({autoDestroy: true, id: 'extcombo-json', fields: ['D','d'], \"data\":[{\"D\":\"Display1\",\"d\":\"Return1\"},{\"D\":\"Display2\",\"d\":\"Return2\"},{\"D\":\"Display3\",\"d\":\"Return3\"}]}),valueField: 'd', displayField: 'D'",
"EXT_BUTTON_SLIDER": ", \"width\": 100, \"minValue\": 0, \"maxValue\": 100",
"EXT_BUTTON_RADIO_YESNO": ", \"items\": [{\"boxLabel\": \"Yes\", \"name\": \"radioyesno\", \"inputValue\": \"Y\"} ,{\"boxLabel\": \"No\", \"name\": \"radioyesno\", \"inputValue\": \"N\", \"checked\": true }], \"fieldLabel\": \"Radio\""
}
</script>
Our region template looks like this (this is an extract of the region template):
<div id="regionButtons#REGION_ID#" style="display:none;">#CLOSE##PREVIOUS##NEXT##DELETE##EDIT##CHANGE##CREATE##CREATE2##EXPAND##COPY##HELP#</div>
<script type="text/javascript">
var tbar#REGION_ID# = Ext.app.cleanButtonJSON("regionButtons#REGION_ID#", "#REGION_ID#");
Ext.onReady({
Ext.app.apExtPanel("panel#REGION_ID#", "#REGION_ID#", tbar#REGION_ID#);
});
</script>
From the above you can see that we call a function named “Ext.app.cleanButtonJSON” before passing the toolbar object to our panel creation function as our JSON objects outputted by our custom templates are malformed (intentionally):
Ext.app.cleanButtonJSON = function (pJsonObj, pRegionId) {
var buttons = new Array();
Ext.select('[id=' + pJsonObj + ']').each(function (el) {
buttons = el.dom.innerHTML.replace(/\$REGION_ID\$/g, pRegionId);
for (var key in extShortcuts) {
buttons = buttons.replace(new RegExp(key, 'g'), extShortcuts[key]);
}
buttons = eval("(" + "[" + new String(Ext.util.Format.stripTags(buttons)).replace(/\}\{/g, "\},\{") + "]" + ")");
});
if ((!buttons) || (buttons == undefined)) buttons = [];
return buttons;
}
The above javascript function takes the innerHTML of the DIV which contains our buttons. The templates dictate that this is actually JSON and not HTML and we then “eval” it into an actual JSON object on page load. Before we perform the eval we replace our named shortcuts outputted by our templates, that’s why our shortcuts are printed out in an escaped string. This button object is then passed to our function which builds the Panel and adds the object to the “tbar” config parameter, and hey presto we have a slider in our toolbar.
Now the really cool part is that within our shortcuts that we create we define our own substitution strings, for example #LOV:EXT_BUTTON_LOV#. We do this because APEX actually never uses the shortcuts we only ever call them when we build our JSON metadata object in the page header, so we can define them however we like, which includes adding in our own substitution strings. Ok so take the example substitution string which I listed #LOV:EXT_BUTTON_LOV#. What we do with this is extract the LOV name and check the current page to see if an item exists e.g. P6_EXT_BUTTON_LOV, if it does we then extract the LOV definition otherwise we check the application level for a LOV named “EXT_BUTTON_LOV” and extract the query definition. e.g. code extract…
FOR c IN
( SELECT lov_definition lov_sql
FROM apex_application_page_items
WHERE application_id = v('APP_ID')
AND page_id = v('APP_PAGE_ID')
AND regexp_replace(item_name,'P\d+_','') = v_lov
UNION ALL
SELECT list_of_values_query lov_sql
FROM apex_application_lovs
WHERE application_id = v('APP_ID')
AND list_of_values_name = v_lov
) LOOP
In either case we execute the SQL and encode the results into a JSON object which is replaced within our shortcut. e.g. #LOV:EXT_BUTTON_LOV# is replaced with the following JSON object
"data": [{
"D": "Display1",
"d": "Return1"
},
{
"D": "Display2",
"d": "Return2"
},
{
"D": "Display3",
"d": "Return3"
}]
This means that our combo’s can have a consistent definition but different data stores .i.e. on page 6 we have a list of people but on page 7 we have a list of customers, the beauty is that we use the exact same shortcut and thus reducing the amount of code required
Here’s an example of the shortcut with the substitution string
Ok so you’re probably thinking that the above seems over complicated and too many hacky steps , but it’s the end result we’re interested in and the speed of development. Now that we’ve created this structure adding in a combo or slider or other custom elements is as quick as creating a button in the APEX IDE and selecting the appropriate template. So APEX development productivity is not impacted. Plus we have the ability to embed whatever javascript we want executed when a user change event occurs. If anything we are boosting productivity by being easily able to define widgets instead of buttons within a region button bar. The argument for using this implementation Vs a region plugin is that this fits better into our overall framework design and is reused by all our region templates.
If you’re still left scratching your head or thinking that this doesn’t really apply to you, take a step back and think about how flexible APEX is as a development tool. You can basically bend the product to meet your own requirements. It’s a blank canvas and gives you all the tools you need.





