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.
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
Clear the
Enter a New Note
fieldRefresh 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
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
🩳 [APEX Shorts](https://blog.cloudnueva.com/series/apex-shorts)
#️⃣ [APEX Posts](https://blog.cloudnueva.com/tag/orclapex)