APEX 22.2+ Dynamic Content Regions

APEX 22.2+ Dynamic Content Regions

·

5 min read

Introduction

For the longest time, as APEX developers, we have had to utilize workarounds to refresh Dynamic Content regions in APEX dynamically. I even wrote a blog post with an approach I use to solve this problem Solving the APEX PL/SQL Dynamic Content Region Partial Page Refresh Problem. APEX 22.2 brought a new Dynamic Content Region that supports CLOBs and dynamic refreshing out of the box. This post will demonstrate how the new APEX Dynamic Content Region works.

Why Use Dynamic Content Regions

Before starting, let's look at why you would want to use an APEX Dynamic Content Region in the first place. I typically only use them when standard APEX components and templates (e.g., Card Regions, Comments, Content Row, Value Attribute Pairs, etc.) do not fit my requirements. Even then, I would suggest using CSS to modify standard APEX templates before using a Dynamic Content Region.

Dynamic Content Regions are helpful when you need to build HTML content dynamically using PL/SQL. For example, you may need to show data in a non-tabular layout, or you may need to show HTML that has been generated from multiple sources (DB table, REST Services, etc.).

Demonstration

In my demo, we have provided users with a Rich text editor field where they can enter notes. These notes are appended to a CLOB column in a table, and the Dynamic Content Region is refreshed to show the CLOB with all of the notes.

How Dynamic Content Regions Work

An APEX Dynamic Content Region emits whatever HTML you return in the Dynamic Content Region PL/SQL Function Body returning a CLOB attribute. The simplest possible example would look like this:

The output for the above example looks like this:

Demo Code

I made my demo a little more complicated to illustrate all of the features of Dynamic Content Regions.

Oracle APEX Dynamic Content Region UI

Let's look at the code and the APEX page behind this:

Enter Notes Region

The Enter a New Note field is a simple Rich Text Editor Item. There is a button + Add Note which runs a Dynamic Action to:

1. Append the New Note to notes history CLOB in a table

  1. Clear the Enter a New Note field

  2. Refresh the Note History Region so that we see the new notes. ⭐ This is one of the aspects of the new Dynamic Content Region, which differs from APEX versions before 22.2. Being able to refresh a Dynamic Content Region from a Dynamic Action gives us the ability to generate dynamic content without having to submit the page

APEX Dynamic Content Region Enter Notes Region

The complete code for the Server Side code can be seen below. In real life, this code would be inside a PL/SQL package.

DECLARE
  l_notes        cndemo_table.notes%TYPE;
  l_new_note     CLOB;
  l_clob_len     NUMBER;
  GC_ACTIVITY_TPL CONSTANT VARCHAR2(32000) := q'[
<ul class="t-ContentRow t-ContentRow--styleCompact t-ContentRow--hideDescription activity-header t-Report--hideNoPagination u-color-21 margin-bottom-md" id="1" data-region-id="RX_1">
<li class="t-ContentRow-item ">
  <div class="t-ContentRow-wrap">
    <div class="t-ContentRow-body">
      <div class="t-ContentRow-content">
        <h3 class="t-ContentRow-title">Entry Date: #ACTIVITY_NAME#</h3>
      </div>
      </div>
    </div>
  </li>
  </ul>]';
  l_tpl   VARCHAR2(32000);
BEGIN

  -- Replace the token #ACTIVITY_NAME# with the current date and time.
  l_tpl := REPLACE(GC_ACTIVITY_TPL, '#ACTIVITY_NAME#', TO_CHAR(CURRENT_TIMESTAMP,('DD-MON-YYYY HH:MI:SS pm')));

  -- Create a CLOB for the New Note.
  dbms_lob.createtemporary(lob_loc => l_new_note, cache => true, dur => dbms_lob.call);
  l_new_note := :P11_TODAYS_NOTES;

  -- Get the existing note history from a CLOB in a table.
  SELECT notes INTO l_notes
  FROM   cndemo_table
  WHERE  id = 1 FOR UPDATE;

  -- Append the new note content to the CLOB from the table.
  l_clob_len := dbms_lob.getlength(l_notes);
  IF  NVL(l_clob_len,0) = 0 THEN
    -- If there is no note history.
    dbms_lob.createtemporary(lob_loc => l_notes, cache => true, dur => dbms_lob.call);
    l_notes := l_tpl || l_new_note;
  ELSE
    dbms_lob.append(l_notes, l_tpl || l_new_note);
  END IF;

  -- Update the Notes Table with the combined CLOB.
  UPDATE cndemo_table
  SET    notes = l_notes
  WHERE  id = 1;

  -- Free up the temporary CLOB.
  dbms_lob.freetemporary(l_new_note);
END;
  • The constant GC_ACTIVITY_TPL, is there to illustrate that we can use APEX Universal Theme CSS classes to format HTML content in a Dynamic Content Region. I have picked out CSS classes from the 'Content Region' to format the date heading I have between each note

Note History Dynamic Content Region

This is the Dynamic Content Region.

Here is the code from the PL/SQL Function Body returning a CLOB attribute from the screenshot above. Note: this code is just here as an example. Your code could be fetching HTML from a web service, looping through hundreds of records, etc. If you return a CLOB, it will be rendered in the region.

DECLARE
  l_notes     cndemo_table.notes%TYPE;
  l_note_len  NUMBER;
BEGIN
  -- Fetch the Notes History CLOB from a table.
  SELECT notes
  ,      dbms_lob.getlength(notes) note_len
  INTO   l_notes
  ,      l_note_len
  FROM   cndemo_table
  WHERE  id = 1;
  -- If the size of the note is 
  IF  NVL(l_note_len,0) = 0 THEN
    -- If there is no current note then return message to indicate there are no notes. Similar to a Classic Or Interactive Reports region where we have No Data Found.
    RETURN '<h4>You do not have any notes</h4>';
  ELSE
    -- Return the CLOB containing the HTML for the notes.
    -- APEX will display whatever HTML you have in the region.
    RETURN l_notes;
  END IF;
END;

⭐ In the code above, you will notice the other change to Dynamic Content Regions that was introduced in APEX 22.2. In previous versions, you had to output HTML using htp.p or apex_util.prn. From APEX 22.2 on, you simply build a CLOB and return it.

In the Attributes section of the region, we have the option to enable Lazy Loading. This will defer the fetching and rendering of the HTML in the Dynamic Content Region until after the page is rendered. This can be useful if the Dynamic Content Region takes a long time to process, and you don't want the user to have to wait for this before the main page is loaded.

And that is all there is to it!

Guarding Against XSS

One thing I should point out is that APEX will not attempt to do any escaping of the HTML that you emit in a Dynamic Content Region. This means you must either completely trust the content does not have any javascript embedded in it, or you must use APEX_ESCAPE to escape the content yourself.

See the WASP XSS Guide for more details on Cross-Site Scripting (XSS) Attacks.

Conclusion

You should not need to use Dynamic Content Regions often, but they are essential when you do need them. Having the ability to refresh them dynamically (since APEX 22.2) makes them even more useful.

🔗 Read More