Skip to main content

Command Palette

Search for a command to run...

Using IIFEs within Oracle APEX Dynamic Action JavaScript Expressions

Updated
4 min read
Using IIFEs within Oracle APEX Dynamic Action JavaScript Expressions
M

With around 20 years on the job, Matt is one of the most experienced software developers at Pretius. He likes meeting new people, traveling to conferences, and working on different projects.

He’s also a big sports fan (regularly watches Leeds United, Formula 1, and boxing), and not just as a spectator – he often starts his days on a mountain bike, to tune his mind.

Introduction

I have a simple page. A Static Region and an Interactive Grid Region. There are three items on the page of three different types.

I also have this Page Load Dynamic Action which adds a pink class u-color-10 to anything that is found in the Expression.

With this JavaScript Expression, I can use a jQuery selector just like this:

$('.t-PageBody') 

By selecting the t-PageBody class, I can turn the page pink

I don't have to use jQuery, the same works for vanilla JavaScript

document.querySelectorAll('.t-PageBody')

However I could have, and should have, just used the jQuery Selector right? 👇

Yes. Correct. I should have. It just feels more declarative when I just paste in as a selector.

However I could have also used something more programmatic than just a simple selector in my JavaScript Expression😍

This is called an IIFE (Immediately Invoked Function Expression). It's a function that:

  1. Gets defined immediately - (function () { ... })Gets executed immediately - the trailing ()

  2. Returns a value you can use right away

The parentheses around the function make it an expression (not a statement), and the trailing () calls it instantly. 🎉

Items

Let's explore an IIFE in more detail.

In the next example I'm using a jQuery Selector to turn all the input values pink

If you look closely, you can see that not all the inputs have been selected (i.e the Select & Textarea have not been selected), furthermore, the Search on the IG has turned pink too. This is not what I wanted 🤷‍♂️

Maybe I could have used this in my jQuery Selector?

.apex-item-text, .apex-item-select, .apex-item-textarea

It works, however, I needed to inspect all item classes, what if someone adds a new item type to the page? ... also I really don't have much space in Page Designer to type all this in.

Here is where using IIFEs with JavaScript Expressions can help 🎉

I know that all APEX items are held in apex.items along with a selector (element), so I just need to surface them out.

I can do this by using this function:

(function () {
  return Object.values(apex.items)
    .filter(item => item?.element?.length)
    .map(item => item.element[0]);
})()

I place it in a JavaScript Expression like this

This time I get 🎉

I can also adapt it this way to only surface only certain types e.g SELECT & TEXTAREA

(function () {
  const types = ["SELECT", "TEXTAREA"];

  return Object.values(apex.items)
    .filter(item =>
      item?.element?.length &&
      types.includes(item.item_type)
    )
    .map(item => item.element[0]);
})()

I admit that using JavaScript is a bit complicated. However, its just returning an array of elements like this:

(function () {
  const items = [];

  items.push(apex.items.P1_TEXT.node);
  items.push(apex.items.P1_SELECT.node);
  items.push(apex.items.P1_TEXTAREA.node);

  return items;
})()

or like this

(function () {
  return $("#P1_TEXT, #P1_SELECT, #P1_TEXTAREA");
})()

Regions

Regions are a bit more peculiar.

Regions also have an apex.regions equivalent of apex.items. Lets try it out on all regions with this

(function () {
    return $(Object.values(apex.regions)
        .filter(region => region?.element?.length)
        .map(region => region.element[0]));
})()

and we see the IG is selected, but not the static region! This is not what I wanted.

This is because apex.regions only holds widget-like regions (basically any region with a js-apex-region class)

If I actually want to fetch all regions? Here, I combine anything from apex.regions with all regions with class t-Region

(function () {
    return $(Object.values(apex.regions)
        .filter(region => region?.element?.length)
        .map(region => region.element[0]))
        // Add Static Regions
        .add($('.t-Region'));
})()

If you think that apex.regions is sufficient for your needs.. you can also select certain region types like this

(function () {
    const regionTypes = [
        "ClassicReport",
        "DynamicContent",
        "Facets",
        "FullCalendar",
        "InteractiveGrid",
        "InteractiveReport",
        "JetChart",
        "ListView",
        "Partial",
        "ResponsiveTable",
        "Search",
        "SpatialMap",
        "Tree",
        "WorkflowDiagram",
        "TemplateComponent",
        "Cards",
        "generic"
    ];

    return Object.values(apex.regions)
        .filter(region =>
            region?.element?.length &&
            regionTypes.includes(region.type)
        )
        .map(region => region.element[0]);
})()

The above is an exhaustive list that contains all the known Region Types as of APEX 24.2 (well at least the ones I know of), so you can add/remove these however you wish

Conclusion

IIFEs in a JavaScript Expression is pretty powerful as you can write a function to programmatically return elements.

ENJOY

What's the picture? It's Montpellier Mews Antiques Market in Harrogate. The film Hunters Prayer had a scene filmed there in 2014. Visit Yorkshire!