Skip to main content

Command Palette

Search for a command to run...

Preventing "False Positive" Selection Change Events in Interactive Grids

Published
5 min read
M

Software Engineer at Optimizer

If you use Interactive Grids in Oracle APEX, you’ve probably hooked into the Selection Change dynamic action to react when the user changes selected rows. The annoying part: the event can fire twice when the page loads, even though the user hasn’t touched the grid.

This post shows a small JavaScript helper that acts like a selection-aware debounce, so your dynamic action only runs when the selection has actually changed.


TL;DR

  • On some pages, Selection Change [Interactive Grid] fires twice on page load, before the user makes any change.

  • We create a selection fingerprint from the currently selected row IDs and store it on the region element.

  • If the fingerprint hasn’t changed since the last event, we return false from a Client-side Condition, so your dynamic action does not run when there is no actual change.

Scroll down for the full code and step‑by‑step setup.


The Problem

Selection Change [Interactive Grid] is useful, but noisy:

  • It can fire twice on first load, even though the user hasn’t changed the selection.

That means:

  • Unnecessary server calls or refreshes

  • Initialization logic running once “too early”

  • Confusing logs and side effects when nothing appears to have changed


The Idea: Selection “Fingerprint”

The key idea is to treat the current selection as a small fingerprint:

  1. Read the currently selected records from the Interactive Grid.

  2. Convert each record into its record ID.

  3. Sort those IDs and join them into a single string, for example:

    • "1050"

    • "1050:2033"

    • "" (for “no selection”)

  4. Compare this fingerprint with the last stored fingerprint.

  5. Only if they differ do we consider it a real selection change.

We store this fingerprint in the DOM (using jQuery’s .data() attribute on the region element), so it persists across multiple event firings during the same page lifecycle.


The JavaScript Helper

The helper is implemented once in a shared workspace JavaScript file and then reused by any Interactive Grid that needs it.

// File: workspace_utils.js

var Demo = Demo || {};

Demo.checkSelection = function(daContext) {
    try {
        // Automatically find the Region from the context
        const regionElement = daContext.triggeringElement;

        // Safety check: ensure we actually have an element
        if (!regionElement) return false;

        const regionId = regionElement.id; 
        const region = apex.region(regionId);

        if (!region) {
            console.warn("Demo: Region not found", regionId);
            return false;
        }

        // Get Grid and Model
        if (!region.widget()) return false;

        const grid = region.widget().interactiveGrid("getViews", "grid");
        if (!grid || !grid.model) return false;

        const model = grid.model;
        const records = grid.getSelectedRecords() || [];

        // Create "Fingerprint"
        const currentFingerprint = records.map(function(r) {
            return model.getRecordId(r);
        }).sort().join(":");

        // Get last state
        const $el = apex.jQuery(regionElement);
        const lastFingerprint = $el.data("selection-fingerprint");

        // No previous fingerprint yet -> IGNORE
        if (lastFingerprint === undefined) {
            $el.data("selection-fingerprint", currentFingerprint);
            return false;
        }

        // Fingerprint matches last event -> IGNORE
        if (currentFingerprint === lastFingerprint) {
            return false; 
        }

        // Valid Change -> UPDATE & FIRE
        $el.data("selection-fingerprint", currentFingerprint);
        return true;

    } catch (e) {
        console.error("Demo: Error in checkSelection", e);
        return false;
    }
};

How to Use This in Your APEX App

1. Add the helper to a workspace JavaScript file

  1. Create a Workspace Static File called workspace_utils.js.

  2. Paste the Demo.checkSelection function from above into that file.

2. Reference the file in User Interface Attributes

  1. Go to Shared Components → User Interface Attributes → JavaScript.

  2. In File URLs, add:

#WORKSPACE_FILES#workspace_utils#MIN#.js

This way, the helper is automatically loaded and can be used on all pages.


3. Create or Adjust the Dynamic Action

  1. Create a Dynamic Action on your Interactive Grid region:

    • Event: Selection Change [Interactive Grid]

    • Selection Type: Region

    • Region: the Interactive Grid region name

  2. Add your existing True Actions (Execute PL/SQL, Refresh Region, etc.) or create new ones.


4. Use the function as a Client-side Condition

In your Dynamic Action, set Client-side Condition → JavaScript Expression to:

Demo.checkSelection(this)

The helper inspects the Interactive Grid behind the dynamic action, compares the current selection fingerprint with the last stored one, and returns true only when there is a real change in the selected rows.


Why This Works

  • First events on page load:
    There is no stored fingerprint yet (lastFingerprint === undefined).
    The script stores the current selection but returns false, so the action does not run.

  • Events without a real change:
    The selection is identical to the last stored state, so currentFingerprint === lastFingerprint.
    The function returns false, preventing the action from running when nothing has actually changed.

  • Actual user selection change:
    The selected rows are different, so the fingerprint string changes.
    The script updates the stored fingerprint and returns true, allowing the dynamic action to fire.

This simple comparison lets you acknowledge that Selection Change may fire on load while ensuring your dynamic action only runs when the selection really changes.


Variations and Notes

  • Multiple grids:
    You can reuse this logic for multiple grids simply by using Demo.checkSelection(this) as the Client-side Condition expression in each Interactive Grid’s Dynamic Action.

  • Performance:
    For typical grid sizes, mapping record IDs and joining them is very cheap. Even for larger grids, this runs only when the Selection Change event fires.

  • Empty selection:
    No selection becomes an empty string "". The comparison still works correctly and suppresses redundant events.


Closing Thoughts

The Selection Change event of an Oracle APEX Interactive Grid can be noisy, especially on page load. By creating and comparing a lightweight selection fingerprint, you can make sure your dynamic actions fire only when the user really changes the selection.

Once you drop this helper into your app, Interactive Grid behavior becomes much more predictable and you avoid unnecessary processing and confusing side effects in your APEX applications.