<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[APEX Blog]]></title><description><![CDATA[Blog about Oracle APEX]]></description><link>https://apexblog.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1763650313106/b438bec5-e214-4c61-9bf1-381c2af1797f.png</url><title>APEX Blog</title><link>https://apexblog.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 15 Apr 2026 06:11:58 GMT</lastBuildDate><atom:link href="https://apexblog.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Display Report Execution Time with #TIMING# in Oracle APEX]]></title><description><![CDATA[Optimizing performance is a key concern for any Oracle APEX developer, especially when building data-rich dashboards or reports. One simple but effective tool at your disposal is the #TIMING# substitution variable, which allows you to display the ela...]]></description><link>https://apexblog.dev/display-report-execution-time-with-timing-in-oracle-apex</link><guid isPermaLink="true">https://apexblog.dev/display-report-execution-time-with-timing-in-oracle-apex</guid><category><![CDATA[#oracle-apex]]></category><category><![CDATA[Oracle]]></category><category><![CDATA[Timing]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Thu, 29 May 2025 17:45:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/rCOWMC8qf8A/upload/a57c08feb0ec241a801bab8d562ee9f7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Optimizing performance is a key concern for any Oracle APEX developer, especially when building data-rich dashboards or reports. One simple but effective tool at your disposal is the #TIMING# substitution variable, which allows you to display the elapsed execution time for any report region right where your users can see it.</p>
<h2 id="heading-what-is-timing">What Is #TIMING#?</h2>
<p>The *TIMING# substitution variable represents the elapsed time (in seconds) taken to render a region, including the time to fetch data and render region items. This variable is available for use in the footer of any report region (such as Interactive Reports, Classic Reports, or Charts).</p>
<h2 id="heading-why-use-timing">Why Use #TIMING#?</h2>
<ul>
<li><p><strong>Performance Transparency:</strong> Show users how long their reports take to run, helping set expectations for data-heavy queries.</p>
</li>
<li><p><strong>Troubleshooting:</strong> Quickly identify slow-running regions on a page, making it easier to pinpoint and tune problematic queries.</p>
</li>
<li><p><strong>User Communication:</strong> When users request large or complex datasets, the timing info helps explain longer wait times.</p>
</li>
</ul>
<h2 id="heading-how-to-implement-timing-in-your-reports">How to Implement #TIMING# in Your Reports</h2>
<ol>
<li><p><strong>Edit the Report Region:</strong><br /> In Page Designer, select the report region you want to monitor.</p>
</li>
<li><p><strong>Add #TIMING# along with other substitution strings to the Footer:</strong>  </p>
<p> <code>Fetched #ROWS_FETCHED# rows of #TOTAL_ROWS# in #TIMING# seconds</code>  </p>
<p> Special Built-in Region Substitution Strings</p>
<p> | <strong>Substitution String</strong> | <strong>Description</strong> |
 | --- | --- |
 | <code>#ROWS_FETCHED#</code> | Number of rows fetched by the report |
 | <code>#TOTAL_ROWS#</code> | Total number of rows in the query |
 | <code>#TIMING#</code> | Time taken to render the region (in seconds) |
 | <code>#APEX$ROW_NUM#</code> | Row number in Classic Reports |</p>
</li>
<li><p><strong>Save and Run:</strong><br /> Save your changes and run the application. The footer will now display real-time execution metrics every time the report runs.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748540216078/16ce5ee2-9ce7-475f-b23b-e41f79fb1cbb.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-considerations">Considerations</h2>
<ul>
<li><p><strong>Works Per Region:</strong> #TIMING# is available only for report regions, not for the entire page or non-report regions.</p>
</li>
<li><p><strong>Debugging:</strong> For deeper performance analysis, use APEX’s debug mode (LEVEL9) to see detailed execution times for every component.</p>
</li>
</ul>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX Hack: Create a Floating Action Button]]></title><description><![CDATA[Looking to give your Oracle APEX mobile app a modern, native feel? Here’s a quick hack: add a floating action button that stays anchored at the bottom corner just like in popular mobile apps. This small UI tweak can make your app feel more polished a...]]></description><link>https://apexblog.dev/oracle-apex-hack-create-a-floating-action-button</link><guid isPermaLink="true">https://apexblog.dev/oracle-apex-hack-create-a-floating-action-button</guid><category><![CDATA[#oracle-apex]]></category><category><![CDATA[Oracle]]></category><category><![CDATA[CSS]]></category><category><![CDATA[HTML5]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Mon, 26 May 2025 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Tjsp3VyQJ2A/upload/9e24b4e8859bc200acc721c323fb8aa5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Looking to give your Oracle APEX mobile app a modern, native feel? Here’s a quick hack: add a floating action button that stays anchored at the bottom corner just like in popular mobile apps. This small UI tweak can make your app feel more polished and intuitive, especially for mobile-first users.</p>
<h2 id="heading-the-css">The CSS</h2>
<p>A floating action button is a circular button that “floats” above the UI, typically in the lower right corner, providing quick access to a key action (like “Add,” “Create,” or “Scan”). With a bit of CSS and a Universal Theme icon, you can implement this in minutes.</p>
<h2 id="heading-how-to-implement">How to Implement</h2>
<p><strong>Step 1: Add a Button to Your Page</strong></p>
<ul>
<li><p>In Page Designer, add a new Button (e.g., “Add”) to your APEX page.</p>
</li>
<li><p>Set its class to c-floating-bt.</p>
</li>
<li><p>Choose an appropriate icon (like <code>fa-plus</code> or <code>fa-camera</code>).  </p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748538460276/c944f2c7-7be2-464d-bf06-68f28fc92b1a.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<p><strong>Step 2: Apply Custom CSS</strong></p>
<p>Add the following CSS to your page (Page &gt; CSS or in your app’s CSS file):  </p>
<pre><code class="lang-css"><span class="hljs-selector-class">.c-floating-bt</span> {
  <span class="hljs-attribute">position</span>: fixed;
  <span class="hljs-attribute">bottom</span>: <span class="hljs-number">80px</span>;
  <span class="hljs-attribute">right</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">z-index</span>: <span class="hljs-number">100</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">65px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">65px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">4px</span> <span class="hljs-number">12px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">0.2</span>);
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
}
</code></pre>
<p>The button will appear at the bottom right of the page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748538623998/91edf55a-6a69-48a7-9b01-5fb0bb6b594b.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-conclusion">Conclusion</h2>
<ul>
<li><p><strong>Native Feel:</strong> Mimics the UI of leading mobile apps, making your APEX app feel instantly more modern.</p>
</li>
<li><p><strong>User Experience:</strong> Keeps primary actions accessible, reducing taps and scrolling.</p>
</li>
<li><p><strong>Easy to Implement:</strong> Just a button and a few lines of CSS, no plugins or complex code.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[From Forms to APEX: Tackling the Stickiest Migration Issues Head-On]]></title><description><![CDATA[Oracle Forms and APEX are both technologies used to build data centric applications.
APEX uses the best of the modern web to create native web applications. Oracle Forms uses NPAPI plugins relying on Java technologies to render the page. Whilst we co...]]></description><link>https://apexblog.dev/from-forms-to-apex-tackling-the-stickiest-migration-issues-head-on</link><guid isPermaLink="true">https://apexblog.dev/from-forms-to-apex-tackling-the-stickiest-migration-issues-head-on</guid><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Sun, 25 May 2025 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/PviMD8jDeYE/upload/f6308bab2efe6c1ec639c2437e2c39b9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Oracle Forms and APEX are both technologies used to build data centric applications.</p>
<p>APEX uses the best of the modern web to create native web applications. Oracle Forms uses NPAPI plugins relying on Java technologies to render the page. Whilst we could go on and on describing the advantages of one over the other and believe us, there are strong opinions on both sides. We, as APEX enthusiasts, acknowledge that whilst many a Forms-to-APEX redevelopment project can be a trouble-free experience – there are some Oracle Forms features that makes the redevelopment a bit sticky.</p>
<p>Many of these thorny features are due to browser security vs. a standalone client-server application and some are just old-school features which don’t have an easy equivalent in a web application.</p>
<p>Let’s start with a list of Webutil features which cause a problem within APEX. The vast majority of Webutil features are going to be difficult to overcome in APEX. If you’ve never heard of Webutil, it’s an Oracle Forms Library that was built to provide access to modules which typically interact with the clients PC e.g. file system, environment variables, etc. If you try to think of any web page which tries to move files around, start programs or read information about the client PC well… that sounds a little scary, but luckily due to browser security we are protected. It’s that same browser security which prevents an APEX page from leaping outside of the browser performing those undesirable actions.</p>
<p>Let’s look at our list…</p>
<p><strong>Running the Host command</strong><br />Once again, due to browser security, we are unable to run a host command from a web application, and some Oracle Forms needed it to run simple Microsoft windows apps like a calculator or even execute .bat files as part of their functionality.</p>
<p><strong>Manipulate client side files</strong><br />Typically functionality includes, creating a folder on the clients HDD, checking if it exists and creating files in that folder. It’s not uncommon to have this functionality within an Oracle Forms application, and would definitely not be the norm within a web page.</p>
<p><strong>Read information from the client machine (Tool_Env)</strong><br />We can easily authenticate on an APEX application using Active Directory however the browser cannot easily detect the user currently logged to the OS (without some trickery). The username and other client data are not accessible from the browser.</p>
<p><strong>Read and write client side images</strong><br />Within Oracle Forms, you can easily read and write images on the client side without any user interaction.</p>
<p><strong>Integrate with client side OLE2 (e.g. Word and Excel)</strong><br />This feature enables Oracle Forms to open a local copy of Word/Excel on the clients machine, get and set values, and provides many other features including saving and printing. For the same reasons above, your web browser will restrict any OLE2 attempts from APEX; however a typical workaround involves moving that code to the Database and have the Database Server interact with local copies of Word/Excel. (Its not recommended)</p>
<p>In Addition to WebUtil there are some general challenges when comparing a standalone client side application (Forms) to a Web Browser one (APEX).</p>
<p><strong>Print Screen</strong><br />This takes a picture of your Oracle Form and sends it to the printer; whilst attempting the same in APEX (or any web page) would send a responsive A4 layout version to the printer.</p>
<p><strong>Java Beans</strong><br />You can probably run java from your apex application, but you need to do additional work to make it work properly. In Oracle Forms this is straightforward with a java beans area.</p>
<p><strong>Pixel Perfect Positioning</strong><br />In Oracle Forms your items are placed at precise x / y coordinates; in APEX/Rest of the web, the layouts are responsive to the screen size and orientation – this is simplified for the APEX developer by using Universal Theme. Even if you can set the height and weight of items in the browser, it can differ between different browsers.</p>
<p><strong>Multiple Forms Open in the same Run-Time</strong><br />On Forms you can open another form (or even the same form) without closing the previous one.</p>
<p><strong>Function Keys</strong><br />You probably do not need the mouse to work on a form screen, this makes the user experience quite agile, when you move to a web application you lose the ability create shortcuts using function keys as these are reserved for the browser itself.</p>
<p><strong>POST</strong><br />From our experience, this is the most challenging thing to replicate in an APEX environment. Some Oracle Form applications, post the data to make it available through different forms or use it to fire some database trigger validations.</p>
<p><strong>Text_IO</strong><br />With TEXT_IO I can create a file and save it to a local folder. In a web environment, this automatic integration becomes very complicated.</p>
<p>Given the above list, it’s necessary to select the best approach either to replicate that tricky functionality or identify alternatives. There is no simple rule and it is a case of adapting each thorny issue as you encounter them;</p>
<p>A Dynamic Action could be a good or a bad choice to replicate an Oracle Forms Trigger. An Interactive Grid could replace the multi-row data block or you could be in for a world of trouble. There is no tool that takes an Oracle Form and magically creates an APEX page. The approach varies from Form to Form – sometimes two Forms can become one APEX page, and one Form can become many APEX pages.</p>
<p>Conclusion: Absolutely APEX is the best choice to redevelop your legacy Oracle Forms application. Developers can re-apply their SQL &amp; PL/SQL skills to APEX development – making the leap easier. The larger the forms application, the larger the project… naturally. Those thorny issues may cause you to scratch your head; but it’s unlikely that an alternative cannot be found. APEX continues to be the best option for the future direction of your forms application.</p>
]]></content:encoded></item><item><title><![CDATA[Supercharge Reports with HTML Expressions in Oracle APEX]]></title><description><![CDATA[Oracle APEX makes it easy to get data on screen fast, but often, the default tabular output isn’t enough. What if you want to highlight statuses, add icons, or display badges all without writing complex SQL or JavaScript? HTML Expressions: a powerful...]]></description><link>https://apexblog.dev/supercharge-reports-with-html-expressions-in-oracle-apex</link><guid isPermaLink="true">https://apexblog.dev/supercharge-reports-with-html-expressions-in-oracle-apex</guid><category><![CDATA[#oracle-apex]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[CSS]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Sat, 24 May 2025 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/GI1hwOGqGtE/upload/57327c3aaccaef9202e7f67b70cb6447.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Oracle APEX makes it easy to get data on screen fast, but often, the default tabular output isn’t enough. What if you want to highlight statuses, add icons, or display badges all without writing complex SQL or JavaScript? <strong>HTML Expressions</strong>: a powerful feature that lets you transform your reports with just a few lines of markup and template directives.</p>
<h2 id="heading-what-are-html-expressions">What Are HTML Expressions?</h2>
<p>An HTML Expression in Oracle APEX allows you to control how a column’s data is displayed by wrapping it in custom HTML, referencing column values, and using conditional logic—all within the APEX UI<a target="_blank" href="https://rutvikprajapati.hashnode.dev/apex-interactive-report-column-formatting-with-html-expressions">.</a> You’ll find the HTML Expression field in many components, including Interactive Reports, Classic Reports, Cards, and Lists.</p>
<p><strong>Key Benefits:</strong></p>
<ul>
<li><p><strong>Separation of concerns:</strong> Keep UI logic out of your SQL queries.</p>
</li>
<li><p><strong>Security:</strong> Underlying column data is used for downloads and filtering, not your HTML markup.</p>
</li>
<li><p><strong>Flexibility:</strong> Add icons, badges, tooltips, and more dynamically.</p>
</li>
</ul>
<h2 id="heading-how-to-use-html-expressions">How to Use HTML Expressions</h2>
<p><strong>Step 1: Open Page Designer</strong></p>
<ul>
<li><p>Select your report region (Interactive or Classic Report).</p>
</li>
<li><p>Click the column you want to format.</p>
</li>
<li><p>Find the “HTML Expression” property.</p>
</li>
</ul>
<p><strong>Step 2: Reference Column Values</strong></p>
<ul>
<li>Use <code>#COLUMN_NAME#</code> to insert the value of any column in your SQL query.</li>
</ul>
<p>Example: This displays the employee name in bold, followed by their job.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>#ENAME#<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> – #JOB#
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748535524655/9bb3a577-a000-4bc2-b6a4-3e05088ef41a.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-going-further-template-directives">Going Further: Template Directives</h2>
<p>APEX’s Universal Theme supports powerful template directives for conditional logic and dynamic content.</p>
<h2 id="heading-conditional-formatting"><strong>Conditional Formatting</strong></h2>
<p>Show different output based on column values.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>#ENAME#<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> – 
{case JOB/}
  {when PRESIDENT/}
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"color:red;"</span>&gt;</span>#JOB#<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
  {when MANAGER/}
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"color:blue;"</span>&gt;</span>#JOB#<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
  {otherwise/}
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"color:green;"</span>&gt;</span>#JOB#<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
{endcase/}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748536029926/cdfa4c0f-b6b7-4a13-bce1-3f5ba1adedab.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-best-practices">Best Practices</h2>
<ul>
<li><p><strong>Keep SQL clean:</strong> Avoid embedding HTML in your SQL queries. Use HTML Expressions for UI logic.</p>
</li>
<li><p><strong>Hidden columns:</strong> If you need to generate complex HTML or values, create a hidden column in your query and reference it in the HTML Expression.</p>
</li>
<li><p><strong>Security:</strong> The HTML Expression is only rendered in the browser. When users download the report, only the raw data is included, not your HTML, reducing the risk of leaking markup</p>
</li>
</ul>
<p>Check out more examples <a target="_blank" href="https://apex.oracle.com/pls/apex/r/apex_pm/ut/template-directives">here</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Best Practices for FilterObject in Oracle REST Data Services]]></title><description><![CDATA[APIs play a vital role in making easy communication between applications and databases. Oracle REST Data Services (ORDS) offers a robust solution for creating RESTful web services that work with Oracle databases. A nice feature provided by ORDS is th...]]></description><link>https://apexblog.dev/best-practices-for-filterobject-in-oracle-rest-data-services</link><guid isPermaLink="true">https://apexblog.dev/best-practices-for-filterobject-in-oracle-rest-data-services</guid><category><![CDATA[Oracle]]></category><category><![CDATA[REST API]]></category><category><![CDATA[ords]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Wed, 21 May 2025 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1690204426537/81f2e40a-37de-4fc8-b3b8-6d04d1368cc5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>APIs play a vital role in making easy communication between applications and databases. Oracle REST Data Services (ORDS) offers a robust solution for creating RESTful web services that work with Oracle databases. A nice feature provided by ORDS is the FilterObject where developers can optimize data retrieval by applying filtering conditions directly to API endpoints. In this blog post, we will explore its usage with some examples.</p>
<p>FilterObject Syntax</p>
<p>The FilterObject syntax follows a simple and intuitive format. It comprises three main components:</p>
<ol>
<li><p><strong>Column Name</strong>: Specifies the name of the database column on which the filtering will be applied.</p>
</li>
<li><p><strong>Operator</strong>: Defines the filtering operation to be performed, such as equals, greater than, less than, etc.</p>
</li>
<li><p><strong>Value</strong>: Represents the value used for comparison.</p>
</li>
</ol>
<p>Using these components, developers can construct complex filter expressions to cater to various filtering requirements.</p>
<p>FilterObject in Action</p>
<p>Suppose we have an endpoint to retrieve employee data from the emp table. We can use the FilterObject to fetch employees with a specific job title, salary range, or any other relevant criterion.  </p>
<p>To run the examples we are going to see next, we can use the following code and table below.  </p>
<pre><code class="lang-sql"><span class="hljs-keyword">declare</span>
  l_clob    <span class="hljs-keyword">clob</span>;  
<span class="hljs-keyword">begin</span>
  l_clob := apex_web_service.make_rest_request (
                p_url         =&gt; <span class="hljs-string">'https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/'</span>,
                p_http_method =&gt; <span class="hljs-string">'GET'</span>);

  dbms_output.put_line(l_clob);

<span class="hljs-keyword">end</span>;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1690198864662/b95b5be5-a776-4f95-bca5-ea7b07e87123.png" alt class="image--center mx-auto" /></p>
<ol>
<li>Equal ($eq): Supports number, string and dates. The equal filter could be used implicit and explicit.</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-comment">-- returns employee named KING (= 'KING')</span>
<span class="hljs-comment">-- implicit</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"ename":"KING"}
<span class="hljs-comment">-- explicit</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"ename":{"$eq":"KING"}}
</code></pre>
<p>Note: This filtering is case-sensitive when used with strings</p>
<ol>
<li>Not Equal ($ne): Supports number, string and dates.</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-comment">-- returns all employees but KING (!= 'KING')</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"ename":{"$eq":"KING"}}
</code></pre>
<ol>
<li>Less than ($lt) / greater than ($gt): Supports number and dates.</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-comment">-- returns all employees with salary less than 1000 (&lt; 1000)</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"sal":{"$lt":1000}}
<span class="hljs-comment">-- returns all employees with salary greater than 1000 (&gt; 1000)</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"sal":{"$gt":1000}}
</code></pre>
<ol>
<li>Less than ($lte) or equal / greater than or equal ($gte): Supports number and dates</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-comment">-- returns all employees with salary less than 1000 (&lt;= 1000)</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"sal":{"$lte":1000}}
<span class="hljs-comment">-- returns all employees with salary greater than 1000 (&gt;= 1000)</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"sal":{"$gte":1000}}
</code></pre>
<ol>
<li>To search for part of string ($instr) / not part of string ($ninstr): Supports string only.</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-comment">-- returns employees with the letters KI (instr('KI') &gt;0)</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"ename":{"$instr":"KI"}}
<span class="hljs-comment">-- returns employees with the letters KI (instr('KI') = 0)</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"ename":{"$ninstr":"KI"}}
</code></pre>
<ol>
<li>Like ($like): Supports strings only.</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-comment">-- returns employees with name ending with K (emp like '%K')</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"ename":{"$like":"%K"}}
</code></pre>
<ol>
<li>Between ($between): Supports number, string and dates. We call also use null values for dates and numbers.</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-comment">-- returns employees with hiredate between 17-MAY-81 and 17-NOV-81 (hiredate between '17-MAY-81' and '17-NOV-81')</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"HIREDATE":{"$between":["17-MAY-81","17-NOV-81"]}}
<span class="hljs-comment">-- returns employees with salary lest than 1000 (sal &lt;= 1000)</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"SAL":{"$between":[null,1000]}}
</code></pre>
<ol>
<li>Null ($null).</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-comment">-- returns employees with no comission (COMM is null)</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"COMM":{"$null":null}}
</code></pre>
<ol>
<li>And ($and).</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-comment">-- returns employees with salary equal to 5000 and name starting with K (sal = 5000 and name like 'K%')</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"SAL":{"$and":[{"$eq":5000},{"ename":{"$like":"K%"}}]}}
</code></pre>
<ol>
<li>Or ($or).</li>
</ol>
<pre><code class="lang-sql"><span class="hljs-comment">-- returns employees with salary equal to 5000 or 1500 (sal = 5000 or sal = 1500)</span>
https://&lt;your_server&gt;/ords/&lt;workspace&gt;/hr/employees/?q={"SAL":{"$or":[{"$eq":5000},{"sal":{"$eq":1500}}]}}
</code></pre>
<p>Advantages of Using FilterObject:</p>
<ol>
<li><p>Simplified Data Filtering: Simplifies the complexity of data filtering, making it easy for developers to filter queries without the need for complex SQL.</p>
</li>
<li><p>Reduced Network Load: By allowing clients to specify precisely the data they need, unnecessary data transfer is minimized.</p>
</li>
<li><p>Dynamic Filtering: Including FilterObject in the API request enables clients to dynamically adjust filtering criteria based on their specific requirements.</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Download Files in Oracle APEX Using the APEX_HTTP Package]]></title><description><![CDATA[File downloads are a common requirement in Oracle APEX apps, whether you’re letting users export reports, download images, or retrieve documents stored in the database. With APEX 24.2, the apex_http package provides a simple, modern API for downloadi...]]></description><link>https://apexblog.dev/download-files-in-oracle-apex-using-the-apexhttp-package</link><guid isPermaLink="true">https://apexblog.dev/download-files-in-oracle-apex-using-the-apexhttp-package</guid><category><![CDATA[#oracle-apex]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Tue, 06 May 2025 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/XrIfY_4cK1w/upload/2735ecb2f489c4f578db963e6cc77954.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>File downloads are a common requirement in Oracle APEX apps, whether you’re letting users export reports, download images, or retrieve documents stored in the database. With APEX 24.2, the <code>apex_http</code> package provides a simple, modern API for downloading both BLOB and CLOB content, making file delivery more straightforward than ever.</p>
<p>The <code>apex_http</code> package offers PL/SQL procedures to send files (BLOBs or CLOBs) directly to the client browser for download. It handles MIME types, filenames, and ensures the download process is clean by clearing previous output buffers and stopping the APEX engine after the file is sent.</p>
<h2 id="heading-downloading-a-blob-binary-file-example"><strong>Downloading a blob (binary file) example</strong></h2>
<pre><code class="lang-sql"><span class="hljs-keyword">declare</span>
    l_file <span class="hljs-built_in">blob</span>;
    l_content_type varchar2(4000);
    l_filename varchar2(4000);
<span class="hljs-keyword">begin</span>
    <span class="hljs-keyword">select</span> blob_content, mime_type, filename
      <span class="hljs-keyword">into</span> l_file, l_content_type, l_filename
      <span class="hljs-keyword">from</span> apex_application_temp_files
     <span class="hljs-keyword">where</span> <span class="hljs-keyword">name</span> = :p1_file;

    apex_http.download(
        p_blob         =&gt; l_file,
        p_content_type =&gt; l_content_type,
        p_filename     =&gt; l_filename
    );
<span class="hljs-keyword">end</span>;
</code></pre>
<h2 id="heading-downloading-a-clob-text-file-example"><strong>Downloading a clob (text file) example</strong></h2>
<pre><code class="lang-sql"><span class="hljs-keyword">declare</span>
    l_text <span class="hljs-keyword">clob</span>;
<span class="hljs-keyword">begin</span>
    l_text := <span class="hljs-string">'APEX BLOG'</span>;
    apex_http.download(
        p_clob         =&gt; l_text,
        p_content_type =&gt; 'text/plain',
        p_filename     =&gt; 'mytext.txt'
    );
<span class="hljs-keyword">end</span>;
</code></pre>
<p>When you call <code>apex_http.download</code>, it clears any previous output buffer, ensuring that only the intended file is delivered to the user and no other content is included. After the file download is initiated, the procedure automatically calls apex_application.stop_apex_engine, which cleanly ends the page process and prevents further processing or output.</p>
<p>Starting with APEX 24.1, there is also support for a "download" dynamic action, making it even easier to trigger file downloads directly from the user interface without writing custom PL/SQL code. Additionally, you can control whether the file opens directly in the browser or is downloaded as an attachment by using the <code>p_is_inline</code> parameter setting it to true opens the file inline, while false prompts a download.</p>
]]></content:encoded></item><item><title><![CDATA[How to Use APEX_DEBUG for Troubleshooting in Oracle APEX]]></title><description><![CDATA[Oracle APEX offers robust debugging tools that help devs identify issues, optimize performance, and ensure smooth user experiences. The apex_debug package is central to this, providing detailed insight into your app’s behavior at runtime. Here’s a pr...]]></description><link>https://apexblog.dev/how-to-use-apexdebug-for-troubleshooting-in-oracle-apex</link><guid isPermaLink="true">https://apexblog.dev/how-to-use-apexdebug-for-troubleshooting-in-oracle-apex</guid><category><![CDATA[#oracle-apex]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Fri, 02 May 2025 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/F_m44ut3XTw/upload/b315c1caf95148ee48e8285bae41896c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Oracle APEX offers robust debugging tools that help devs identify issues, optimize performance, and ensure smooth user experiences. The <code>apex_debug</code> package is central to this, providing detailed insight into your app’s behavior at runtime. Here’s a practical guide to using <code>apex_debug</code> and related features for debugging and tuning your APEX apps.</p>
<p>How to enable APEX_DEBUG?  </p>
<p>There are several ways to enable debug mode in APEX:</p>
<p><strong>Developer toolbar:</strong> Click the "debug" button in the developer toolbar while running your application.</p>
<p><strong>URL parameter:</strong> Append <code>&amp;p_debug=YES</code> or <code>&amp;p_debug=LEVEL</code> (where level is 1–9) to your application URL for different verbosity levels.</p>
<p><strong>Application property:</strong> Set the application’s debug property to "yes" for persistent debug logging.</p>
<p><strong>APEX_DEBUG API:</strong> Use <code>apex_debug.enable</code> in PL/SQL to programmatically enable debugging for a session.</p>
<h2 id="heading-logging-dynamic-values-and-parameters"><strong>Logging Dynamic Values and Parameters</strong></h2>
<pre><code class="lang-sql">apex_debug.info('My Debug message, showing order_id: %s', p_order_id);
apex_debug.warn('unexpected status: %s', p_status);
apex_debug.error('Warning, my debug error: %s', sqlerrm);
</code></pre>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Procedure</strong></td><td><strong>Purpose &amp; Level</strong></td><td><strong>When to Use</strong></td></tr>
</thead>
<tbody>
<tr>
<td><code>apex_debug.error</code></td><td>Level 1 (Critical error)</td><td>For logging critical errors or failures that require immediate attention or may halt processing.</td></tr>
<tr>
<td><code>apex_debug.warn</code></td><td>Level 2 (Warning)</td><td>For logging important, non-critical issues that should be reviewed but do not stop processing.</td></tr>
<tr>
<td><code>apex_</code><a target="_blank" href="http://debug.info"><code>debug.info</code></a></td><td>Level 4 (Informational, default level)</td><td>For routine information, such as variable values, process steps, or general progress messages.</td></tr>
<tr>
<td><code>apex_debug.trace</code></td><td>Level 6 (Trace)</td><td>For detailed, low-level tracing of code execution, such as inside loops or complex logic blocks.</td></tr>
</tbody>
</table>
</div><h2 id="heading-view-the-debug-messages"><strong>View the debug messages</strong></h2>
<p>To view the debug messages, click on "View Debug" in the dev toolbar, or go to Utilities / Debug Messages, or also running the following query:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> *
<span class="hljs-keyword">from</span> apex_debug_messages
</code></pre>
<h2 id="heading-logging-in-loops-and-bulk-operations"><strong>Logging in Loops and Bulk Operations</strong></h2>
<p>Be careful when logging too many messages, for example, inside a loop. Be aware of APEX flood control, which limits the number of debug messages per page view (the default is 50,000).</p>
<p>You can check this limit with the query below (run as sys).  </p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> *
<span class="hljs-keyword">from</span> APEX_INSTANCE_PARAMETERS
<span class="hljs-keyword">where</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'DEBUG_MESSAGE_PAGE_VIEW_LIMIT'</span>;
</code></pre>
<h2 id="heading-debugging-outside-apex-applications"><strong>Debugging Outside APEX Applications</strong></h2>
<p>You can use <code>apex_debug</code> in standalone PL/SQL scripts or jobs:</p>
<pre><code class="lang-sql">apex_session.create_session(p_app_id=&gt;101, p_page_id=&gt;1, p_username=&gt;'RODRIGO');
apex_debug.enable(apex_debug.c_log_level_info);
apex_debug.info('My debug message from sql developer');
apex_session.detach;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748015448351/849c2801-35e6-4618-a703-a0126414323b.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748015510521/1466fd89-ae4e-4461-85ae-b282a7dc0477.png" alt class="image--center mx-auto" /></p>
<p>The APEX debug feature is very powerful and useful. To help you troubleshoot issues, enable debug mode and use the browser’s developer tools to inspect AJAX calls and dynamic actions. The debug log will display the sequence and timing of events, helping you identify problems with client-side interactivity.</p>
]]></content:encoded></item><item><title><![CDATA[Generating Barcodes in Oracle APEX with the APEX_BARCODE Package]]></title><description><![CDATA[The apex_barcode package offers a PL/SQL API to generate various types of barcodes. You can output barcodes as SVG (Scalable Vector Graphics) values or as PNG file blobs, making it easy to embed them in your APEX apps, reports, or documents.
Generati...]]></description><link>https://apexblog.dev/generating-barcodes-in-oracle-apex-with-the-apexbarcode-package</link><guid isPermaLink="true">https://apexblog.dev/generating-barcodes-in-oracle-apex-with-the-apexbarcode-package</guid><category><![CDATA[#oracle-apex]]></category><category><![CDATA[barcode]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Wed, 30 Apr 2025 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/_WccNTUvnPU/upload/8a76aa8275588e5c50570a8997f86096.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The <code>apex_barcode</code> package offers a PL/SQL API to generate various types of barcodes. You can output barcodes as SVG (Scalable Vector Graphics) values or as PNG file blobs, making it easy to embed them in your APEX apps, reports, or documents.</p>
<h2 id="heading-generating-a-png-barcode">Generating a PNG barcode</h2>
<pre><code class="lang-sql"><span class="hljs-keyword">declare</span>
  l_output <span class="hljs-built_in">blob</span>;
<span class="hljs-keyword">begin</span>
  l_output := apex_barcode.get_code128_png(
                  p_value            =&gt; <span class="hljs-string">'https://apexblog.dev/'</span>,
                  p_scale            =&gt; <span class="hljs-number">1</span>,
                  p_foreground_color =&gt; <span class="hljs-string">'#4cd964'</span>,
                  p_background_color =&gt; <span class="hljs-string">'#c7c7cc'</span> );

<span class="hljs-keyword">end</span>;
</code></pre>
<h2 id="heading-generating-a-svg-barcode">Generating a SVG barcode</h2>
<pre><code class="lang-sql"><span class="hljs-keyword">declare</span>
  l_output <span class="hljs-keyword">clob</span>;
<span class="hljs-keyword">begin</span>
  l_output := apex_barcode.get_code128_svg(
                  p_value            =&gt; <span class="hljs-string">'https://apexblog.dev/'</span>,
                  p_foreground_color =&gt; <span class="hljs-string">'#4cd964'</span>,
                  p_background_color =&gt; <span class="hljs-string">'#c7c7cc'</span> );

  dbms_outout.put_line( l_output );
<span class="hljs-keyword">end</span>;
</code></pre>
<p>We can also generate in a EAN8 format using <code>apex_barcode.get_ean8_png</code> and <code>apex_barcode.get_ean8_svg</code></p>
<h2 id="heading-embedding-barcodes-in-apex-pages"><strong>Embedding barcodes in APEX pages</strong></h2>
<ul>
<li><p>for svg: use a pl/sql dynamic content region to output the svg directly.</p>
</li>
<li><p>for png: store the blob in a table and use an image item or blob download link to display or let users download the barcode.</p>
</li>
</ul>
<p>In conclusion, the <code>apex_barcode</code> package in Oracle APEX 24.2 provides a robust and flexible solution for generating barcodes in your applications. With support for both SVG and PNG outputs, it caters to a wide range of needs, whether for web integration, print, or other systems. By leveraging this PL/SQL-driven package, you can easily embed barcodes in APEX pages. Whether you need to display barcodes directly on a page or allow users to download them, the <code>apex_barcode</code> package simplifies the process, making it an essential tool for modern APEX dev.</p>
]]></content:encoded></item><item><title><![CDATA[Managing and Updating JSON Data with DML Operations]]></title><description><![CDATA[In the world of Oracle development today, working with JSON data has become an essential skill.
As modern applications increasingly depend on the flexibility of semi-structured data and the seamless integration offered by RESTful services, understand...]]></description><link>https://apexblog.dev/managing-and-updating-json-data-with-dml-operations</link><guid isPermaLink="true">https://apexblog.dev/managing-and-updating-json-data-with-dml-operations</guid><category><![CDATA[#oracle-apex]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Tue, 22 Apr 2025 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/HfFoo4d061A/upload/2289218ea875a3622db70f3159129f68.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the world of Oracle development today, working with JSON data has become an essential skill.</p>
<p>As modern applications increasingly depend on the flexibility of semi-structured data and the seamless integration offered by RESTful services, understanding JSON is more important than ever.</p>
<p>With Oracle Database 21c and its subsequent versions, you have the advantage of managing and updating JSON documents directly within your tables. Thanks to powerful native SQL functions, there's no need for complex PL/SQL or manual parsing anymore.</p>
<h2 id="heading-why-use-native-json-dml-operations"><strong>Why use native JSON DML operations?</strong></h2>
<ul>
<li><p><strong>Performance:</strong> Native functions like <code>json_transform</code> and <code>json_mergepatch</code> are optimized for speed.</p>
</li>
<li><p><strong>Simplicity:</strong> Update, insert, or remove fields in json documents with a single sql statement.</p>
</li>
<li><p><strong>Flexibility:</strong> Works with columns of type <code>json</code>, <code>clob</code>, <code>varchar2</code>, or <code>blob</code></p>
</li>
</ul>
<p>To start lets create a simple table with only two columns</p>
<pre><code class="lang-sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> orders (
    order_id <span class="hljs-built_in">number</span> 
        <span class="hljs-keyword">generated</span> <span class="hljs-keyword">by</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">on</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">as</span> <span class="hljs-keyword">identity</span>
        <span class="hljs-keyword">constraint</span> orders_pk primary <span class="hljs-keyword">key</span>
        <span class="hljs-keyword">not</span> <span class="hljs-literal">null</span>,
    order_data <span class="hljs-keyword">clob</span>
);
</code></pre>
<p>and insert a JSON into order_data</p>
<pre><code class="lang-sql"><span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> orders(order_data) <span class="hljs-keyword">values</span> (<span class="hljs-string">'{
  "order_id": 1001,
  "customer": {
    "customer_id": 501,
    "name": "jane smith",
    "email": "jane.smith@example.com"
  },
  "items": [
    {
      "item_id": 2001,
      "product": "laptop",
      "quantity": 1,
      "price": 1200.00
    },
    {
      "item_id": 2002,
      "product": "mouse",
      "quantity": 2,
      "price": 25.50
    }
  ],
  "status": "processing",
  "order_date": "2025-05-23t14:30:00z",
  "shipping": {
    "address": "123 main street, leeds, uk",
    "method": "express",
    "cost": 15.00
  },
  "last_updated": "2025-05-23t14:30:00z"
}
'</span>);
</code></pre>
<p>If we run a simple query (<code>select order_data from orders</code>), we can see the full JSON. However, we can easily filter it to show only the important data using the code below. In the example, I only want to see the order status.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> order_id,
       json_value(order_data, <span class="hljs-string">'$.status'</span>) <span class="hljs-keyword">as</span> <span class="hljs-keyword">status</span>
<span class="hljs-keyword">from</span> orders
<span class="hljs-keyword">where</span> order_id = <span class="hljs-number">1</span>;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748008306927/1c0cba07-36c9-4c9a-aa29-3aa32e2fc5fb.png" alt class="image--center mx-auto" /></p>
<p>Using <code>json_transform</code>, we can easily update this field.This updates the <code>status</code> field to "shipped" for order 1. if the field doesn't exist, it is created (upsert behavior)</p>
<pre><code class="lang-sql"><span class="hljs-keyword">update</span> orders
<span class="hljs-keyword">set</span> order_data = json_transform(order_data,
    <span class="hljs-keyword">set</span> <span class="hljs-string">'$.status'</span> = <span class="hljs-string">'shipped'</span>)
<span class="hljs-keyword">where</span> order_id = <span class="hljs-number">1</span>;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748008441233/bd60e97d-96ea-4ba6-b711-a02baac0c358.png" alt class="image--center mx-auto" /></p>
<p>You can also update several fields in a single statement. Only the changed fragments of the json are rewritten for efficiency.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">update</span> orders
<span class="hljs-keyword">set</span> order_data = json_transform(order_data,
    <span class="hljs-keyword">set</span> <span class="hljs-string">'$.status'</span> = <span class="hljs-string">'delivered'</span>,
    <span class="hljs-keyword">set</span> <span class="hljs-string">'$.last_updated'</span> = systimestamp)
<span class="hljs-keyword">where</span> order_id = <span class="hljs-number">1</span>;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748011301475/42a91bd4-0751-43dc-b03f-89cfe0a7122c.png" alt class="image--center mx-auto" /></p>
<p>We can remove a field from json. The code below removes the <code>last_updated</code> field if it exists.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">update</span> orders
<span class="hljs-keyword">set</span> order_data = json_transform(order_data,
    remove <span class="hljs-string">'$.last_updated'</span>)
<span class="hljs-keyword">where</span> order_id = <span class="hljs-number">1</span>;
</code></pre>
<p>It's also possible to update the JSON using <code>json_mergepatch</code> with a single set statement by passing the part of the JSON that needs to be updated.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">update</span> orders
<span class="hljs-keyword">set</span> order_data = json_mergepatch(order_data, <span class="hljs-string">'{"status":"delivered"}'</span>)
<span class="hljs-keyword">where</span> order_id = <span class="hljs-number">1</span>;
</code></pre>
<h2 id="heading-best-practices">Best Practices</h2>
<ul>
<li><p>Prefer native json functions (<code>json_transform</code>, <code>json_mergepatch</code>) over manual pl/sql parsing for better performance and maintainability.</p>
</li>
<li><p>Use the <code>json</code> data type (oracle 21c+) for optimal storage and partial updates.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Secure Your Data Effectively Using OCI Data Safe's Data Masking]]></title><description><![CDATA[Oracle Data Safe offers a robust solution for securing sensitive information through its data masking feature. This blog will show the capabilities and benefits of Oracle Data Safe's data masking, highlighting how it helps to maintain data security a...]]></description><link>https://apexblog.dev/secure-your-data-effectively-using-oci-data-safes-data-masking</link><guid isPermaLink="true">https://apexblog.dev/secure-your-data-effectively-using-oci-data-safes-data-masking</guid><category><![CDATA[#oracle-apex]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Wed, 12 Mar 2025 21:30:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741814878445/6892f1e6-27fc-4027-bef7-a383d7ed1be7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Oracle Data Safe offers a robust solution for securing sensitive information through its data masking feature. This blog will show the capabilities and benefits of Oracle Data Safe's data masking, highlighting how it helps to maintain data security and compliance.</p>
<h2 id="heading-whats-data-masking">What’s data masking?</h2>
<p>Data masking is the process of permanently replacing sensitive data with fake but realistic-looking data to protect confidential information. This is used to protect sensitive data to comply with privacy laws and standards. This process should be irreversible and realistic enough for non-production use while maintaining the app functionality.</p>
<h2 id="heading-key-features-of-data-masking"><strong>Key Features of Data Masking</strong></h2>
<ol>
<li><p><strong>Predefined Masking Formats</strong>: Oracle Data Safe offers a comprehensive set of predefined masking formats for common sensitive data types such as names, Social Security numbers, credit card numbers, and email addresses. These formats ensure that masked data is realistic and passes specific validation checks, such as Luhn validation for credit card numbers.</p>
</li>
<li><p><strong>Custom Masking Formats</strong>: Users can create custom masking formats tailored to their specific needs. This flexibility allows organizations to mask data in ways that are unique to their business requirements.</p>
</li>
<li><p><strong>Conditional Masking</strong>: Data can be masked based on predefined conditions, allowing for more nuanced control over how data is protected.</p>
</li>
<li><p><strong>Reversible Masking</strong>: While most masking formats are irreversible to ensure security, Oracle Data Safe supports reversible masking through encryption, allowing authorized users to restore the original data when necessary.</p>
</li>
<li><p><strong>Multi-Database Support</strong>: Data masking can be applied across various Oracle database versions and environments, including on-premises and cloud databases</p>
</li>
</ol>
<p>It’s possible to use this feature on-premises or in OCI. The example in this blog is on how to use it in OCI.</p>
<p><strong>Masking Policies:</strong> To begin, we need to create policies to protect the data.</p>
<p>On Oracle Cloud, go to Oracle Database and under Data Safe, select Data Masking. On Related Resources, select Masking Policies.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741809338947/063b090f-d8b2-4b4c-b93b-43cf5e3795b7.png" alt class="image--center mx-auto" /></p>
<p>We can either upload a previously saved masking policy or create a new one. We are going to create one.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741809614965/64181e54-6e15-4a80-9972-e4868a723f89.png" alt class="image--center mx-auto" /></p>
<p>In this step, we can use a sensitive data model or manually select the sensitive data associated with our target database. In this blog, we are using the second option; however, in my next blog, I will show how to use OCI to generate a sensitive data model.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741810571905/ae299dc3-16e3-4551-bc1c-37f72d2e0c71.png" alt class="image--center mx-auto" /></p>
<p>With the masking policy created, we can start adding the columns we want to mask. After clicking on "Add Column," we can select the schema, table, and columns we want to mask. We will mask ENAME, SAL, and HIREDATE, selecting the sensitive type according to the type of data.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741811603166/e0c1c2c1-5a2c-459c-927a-390a77d840a3.png" alt class="image--center mx-auto" /></p>
<p>After clicking on "Add Columns," we will be able to confirm the mask used for each column.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741811944922/b65e4282-a5e5-41d5-87b2-0710f9656b63.png" alt class="image--center mx-auto" /></p>
<p>With the police done we can go back to the main Data Masking page and do the “Pre-Masking Check“, this will insure the database is ready for the masking. One of the checks looks for the database permissions for the users that is running the masking. By default, an Autonomous Database comes with a database account specifically created for Oracle Data Safe named <code>DS$ADMIN</code>. The roles that you grant to this account determine the Oracle Data Safe features that you can use with your Autonomous Database.</p>
<p>For an Autonomous Database, all roles are already granted by default, except for <code>DS$DATA_MASKING_ROLE</code> and <code>DS$SQL_FIREWALL_ROLE</code>. To grant the role we can run the command below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741813319922/1d397ff0-d8a0-4a11-a079-e2c6cf4707cb.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-sql"><span class="hljs-keyword">EXECUTE</span> DS_TARGET_UTIL.GRANT_ROLE(<span class="hljs-string">'role_name'</span>);
</code></pre>
<p>After the “Pre-Masking Check“, we can now execute the Data Masking, but before that, let's look at the data to compare it with after the masking is done.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741813596071/059d7dc2-fe00-4e22-ba55-32c0cff2ced2.png" alt class="image--center mx-auto" /></p>
<p>We can now go to the main page and click on “Mask Sensitive Data.” Below, we can see the results.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741813748324/a27f7979-95c5-4789-b04b-8b7990481d76.png" alt class="image--center mx-auto" /></p>
<p>Returning to the application, we can now see that the data has been changed, and the columns ENAME, SAL, and HIREDATE have different data.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741813905653/f876330a-29f7-49c2-9546-46f8364a2d15.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Analyzing App Dependencies in Oracle APEX]]></title><description><![CDATA[Oracle APEX 24.1 brings an exciting new feature that makes it easier to analyze application dependencies: the APEX_APP_OBJECT_DEPENDENCY API. This tool is a significant advancement for developers who are handling complex APEX applications or dealing ...]]></description><link>https://apexblog.dev/analyzing-app-dependencies-in-oracle-apex</link><guid isPermaLink="true">https://apexblog.dev/analyzing-app-dependencies-in-oracle-apex</guid><category><![CDATA[#oracle-apex]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Wed, 05 Mar 2025 21:11:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/fPkvU7RDmCo/upload/86d03ee5014e652a81b014af4a447b56.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Oracle APEX 24.1 brings an exciting new feature that makes it easier to analyze application dependencies: the APEX_APP_OBJECT_DEPENDENCY API. This tool is a significant advancement for developers who are handling complex APEX applications or dealing with schemas that have many objects.</p>
<p>As APEX applications grow in complexity, keeping track of database object dependencies becomes increasingly challenging. The new APEX_APP_OBJECT_DEPENDENCY API addresses several common concerns:</p>
<ul>
<li><p>Identifying which database objects are used by specific applications</p>
</li>
<li><p>Determining if dropping a schema object might break an application</p>
</li>
<li><p>Verifying if all SQL and PL/SQL in every page of an application runs without errors</p>
</li>
</ul>
<h2 id="heading-how-it-works"><strong>How It Works</strong></h2>
<p>Simply run the following PL/SQL code in your workspace. This will scan your entire app, analyzing references to schema objects in regions, SQL queries, PL/SQL processes, and even plugins</p>
<pre><code class="lang-sql"><span class="hljs-keyword">BEGIN</span>
    apex_app_object_dependency.scan ( p_application_id =&gt; :app_id );
<span class="hljs-keyword">END</span>;
</code></pre>
<p>The results of the scan are saved until:</p>
<ul>
<li><p>a new scan initiates</p>
</li>
<li><p><code>apex_app_object_dependency.clear_cache</code> is called</p>
</li>
<li><p>the Oracle APEX instance is upgraded</p>
</li>
</ul>
<h2 id="heading-viewing-the-results">Viewing the results</h2>
<p>After running the scan, you can query the results using three new views:</p>
<ol>
<li><p>APEX_USED_DB_OBJECTS: This view lists each schema object used at least once in your app:</p>
<pre><code class="lang-sql"> <span class="hljs-keyword">select</span>
   referenced_type, referenced_owner,
   referenced_name, referenced_sub_name,
   usage_count
 <span class="hljs-keyword">from</span> apex_used_db_objects
 <span class="hljs-keyword">where</span> application_id = :app_id;
</code></pre>
</li>
<li><p>APEX_USED_DB_OBJECT_COMP_PROPS: This view shows each component property in your app that references at least one schema object:  </p>
<pre><code class="lang-sql"> <span class="hljs-keyword">select</span>
   page_id,
   component_type_name, component_display_name,
   property_group_name, property_name
 <span class="hljs-keyword">from</span> apex_used_db_object_comp_props
 <span class="hljs-keyword">where</span> application_id = :app_id;
</code></pre>
</li>
<li><p>APEX_USED_DB_OBJ_DEPENDENCIES: This view displays all DB objects referenced by each component property:  </p>
<pre><code class="lang-sql"> <span class="hljs-keyword">select</span>
   page_id,
   component_type_name, component_display_name,
   property_group_name, property_name,
   code_fragment,
   referenced_type, referenced_owner,
   referenced_name, referenced_sub_name
 <span class="hljs-keyword">from</span> apex_used_db_obj_dependencies
 <span class="hljs-keyword">where</span> application_id = :app_id;
</code></pre>
</li>
</ol>
<h2 id="heading-limitations"><strong>Limitations</strong></h2>
<ul>
<li><p>Results are wiped when APEX is upgraded to a new version, requiring a re-scan of applications</p>
</li>
<li><p>The reports do not include recursive dependencies (e.g., underlying tables of a view)</p>
</li>
<li><p>Dep<a target="_blank" href="https://jeffkemponoracle.com/2024/06/apex-app-object-dependencies/">e</a>ndencies arising from dynamic SQL or PL/SQL (using "execute immediate") are not reported.</p>
</li>
</ul>
<h2 id="heading-improving-the-scan">Improving the scan</h2>
<p>The dependency analyzer specifically identifies connections to individual functions and procedures within packages that have been compiled with PL/Scope. Before starting the analysis, you can choose to recompile the relevant schema(s) with PL/Scope enabled to improve detection capabilities  </p>
<pre><code class="lang-sql"><span class="hljs-keyword">alter</span> <span class="hljs-keyword">session</span> <span class="hljs-keyword">set</span> plscope_settings=<span class="hljs-string">'identifiers:all'</span>;
exec sys.dbms_utility.compile_schema(user, true);
<span class="hljs-keyword">alter</span> <span class="hljs-keyword">session</span> <span class="hljs-keyword">set</span> plscope_settings=<span class="hljs-string">'identifiers:none'</span>;
</code></pre>
]]></content:encoded></item><item><title><![CDATA[APEX Collapsable Region add-ons]]></title><description><![CDATA[Oracle APEX collapsible regions are great because they save space by letting us hide regions we don't need. However, there are a few missing features that would make these regions much better if implemented.

Expand and collapse all: I miss a dynamic...]]></description><link>https://apexblog.dev/apex-collapsable-region-add-ons</link><guid isPermaLink="true">https://apexblog.dev/apex-collapsable-region-add-ons</guid><category><![CDATA[#oracle-apex]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Thu, 27 Feb 2025 00:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738186425993/02eb6c84-15af-432c-9647-2e53112430d9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Oracle APEX collapsible regions are great because they save space by letting us hide regions we don't need. However, there are a few missing features that would make these regions much better if implemented.</p>
<ol>
<li><p>Expand and collapse all: I miss a dynamic action to collapse and expand all to make it easy to find a region on a page with multiple regions. We have the dynamic action to colapse tree but not regions.</p>
</li>
<li><p>Save the collapsible state beyond the session: Currently, we can save the collapsible state, but unfortunately, it's only saved for the session. If I collapse a region that isn't important to me, logging off and logging in again resets my chosen state.</p>
</li>
</ol>
<p>In the video below, I have a page with 4 collapsible regions and two buttons that can collapse and expand all regions at the same time. If only the 4th region is important to me, when I collapse all, I can easily open wihout scrooling. In the second part of the video, I log off and log in again, and instead of resetting, the state of the region is saved.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/-ttGGyavidA">https://youtu.be/-ttGGyavidA</a></div>
<p> </p>
<p>To add those features, I’ve created the JavaScript below where I use apex.storage to save the collapsible region state when users click to expand or collapse. When the page loads, this JS also restores the regions to the saved state.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Function to collapse all collapsible regions</span>
<span class="hljs-built_in">window</span>.collapseAll = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> (!apex.storage.hasLocalStorageSupport()) <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">const</span> storage = apex.storage.getScopedLocalStorage({
        <span class="hljs-attr">applicationId</span>: apex.env.APP_ID,
        <span class="hljs-attr">pageId</span>: apex.env.PAGE_ID,
        <span class="hljs-attr">usePageId</span>: <span class="hljs-literal">true</span>
    });

    $(<span class="hljs-string">'.a-Collapsible'</span>).each(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> regionId = $(<span class="hljs-built_in">this</span>).attr(<span class="hljs-string">'id'</span>);
        storage.setItem(regionId, <span class="hljs-string">'C'</span>);
        $(<span class="hljs-built_in">this</span>).collapsible(<span class="hljs-string">'collapse'</span>);
    });
};

<span class="hljs-comment">// Function to expand all collapsible regions</span>
<span class="hljs-built_in">window</span>.expandAll = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> (!apex.storage.hasLocalStorageSupport()) <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">const</span> storage = apex.storage.getScopedLocalStorage({
        <span class="hljs-attr">applicationId</span>: apex.env.APP_ID,
        <span class="hljs-attr">pageId</span>: apex.env.PAGE_ID,
        <span class="hljs-attr">usePageId</span>: <span class="hljs-literal">true</span>
    });

    $(<span class="hljs-string">'.a-Collapsible'</span>).each(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> regionId = $(<span class="hljs-built_in">this</span>).attr(<span class="hljs-string">'id'</span>);
        storage.setItem(regionId, <span class="hljs-string">'S'</span>);
        $(<span class="hljs-built_in">this</span>).collapsible(<span class="hljs-string">'expand'</span>);
    });
};

<span class="hljs-comment">// Initialization with state restoration</span>
$(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
<span class="hljs-meta">    'use strict'</span>;

    <span class="hljs-comment">// Configure scoped storage  </span>
    <span class="hljs-keyword">const</span> storage = apex.storage.getScopedLocalStorage({  
        <span class="hljs-attr">applicationId</span>: apex.env.APP_ID,  
        <span class="hljs-attr">pageId</span>: apex.env.PAGE_ID,  
        <span class="hljs-attr">usePageId</span>: <span class="hljs-literal">true</span>  
    }); 

    <span class="hljs-comment">// Restore states on page load</span>
    $(<span class="hljs-built_in">window</span>).on(<span class="hljs-string">'apexwindowload'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{  
        $(<span class="hljs-string">'.t-Region--hideShow'</span>).each(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{  
            <span class="hljs-keyword">const</span> $region = $(<span class="hljs-built_in">this</span>);  
            <span class="hljs-keyword">const</span> state = storage.get($region.attr(<span class="hljs-string">'id'</span>));  
            <span class="hljs-keyword">if</span> (state === <span class="hljs-string">'C'</span>) {  
                $region.collapsible(<span class="hljs-string">'collapse'</span>, {<span class="hljs-attr">duration</span>: <span class="hljs-number">0</span>});  
            } <span class="hljs-keyword">else</span> {  
                $region.collapsible(<span class="hljs-string">'expand'</span>, {<span class="hljs-attr">duration</span>: <span class="hljs-number">0</span>});  
            }  
        });  
    }); 

    <span class="hljs-comment">// Persist state changes</span>
    $(<span class="hljs-built_in">document</span>).on(<span class="hljs-string">'apexaftertoggle'</span>, <span class="hljs-string">'.t-Region'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">e, data</span>) </span>{  
        <span class="hljs-keyword">const</span> regionId = $(<span class="hljs-built_in">this</span>).attr(<span class="hljs-string">'id'</span>);  
        storage.set(regionId, data.collapsed ? <span class="hljs-string">'C'</span> : <span class="hljs-string">'S'</span>);  
    });  

    <span class="hljs-comment">// Button click handlers</span>
    apex.jQuery(<span class="hljs-built_in">document</span>).on(<span class="hljs-string">"click"</span>, <span class="hljs-string">"#EXPAND_BTN"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        expandAll();
    });

    apex.jQuery(<span class="hljs-built_in">document</span>).on(<span class="hljs-string">"click"</span>, <span class="hljs-string">"#COLLAPSE_BTN"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        collapseAll();
    });
});
</code></pre>
<p>I recommend you create the JavaScript above as a static file and reference it at the app level if you use collapsible regions throughout the app.</p>
<p>For the buttons, create two buttons as the following  </p>
<p>Label: Collapse All<br />Behavior: Redirect to URL<br />URL: javascript:void(0);<br />Static ID: COLLAPSE_BTN  </p>
<p>Label: Expand All<br />Behavior: Redirect to URL<br />URL: javascript:void(0);<br />Static ID: EXPAND_BTN  </p>
<p>Enjoy!</p>
]]></content:encoded></item><item><title><![CDATA[How to Fire a Close Event on Dialog X Button Click]]></title><description><![CDATA[By default, the X button on dialog pages cancels and closes the dialog when clicked. Today, I came across a situation where I needed to trigger a dialog close dynamic action on the parent page whenever the dialog is closed. However, I can't rely on u...]]></description><link>https://apexblog.dev/how-to-fire-a-close-event-on-dialog-x-button-click</link><guid isPermaLink="true">https://apexblog.dev/how-to-fire-a-close-event-on-dialog-x-button-click</guid><category><![CDATA[modal dialog]]></category><category><![CDATA[#oracle-apex]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Wed, 19 Feb 2025 10:36:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739961567537/eecaa558-02ac-4d3e-b0fc-b657f67060ef.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>By default, the X button on dialog pages cancels and closes the dialog when clicked. Today, I came across a situation where I needed to trigger a dialog close dynamic action on the parent page whenever the dialog is closed. However, I can't rely on users always clicking my dialog close button. I could remove the X button, but I want to keep it consistent with all other dialogs.</p>
<h2 id="heading-overriding-the-default-x-button-behavior"><strong>Overriding the Default X button Behavior</strong></h2>
<ol>
<li>Define a custom JavaScript function to trigger a custom event when the dialog closes. Add this function to your page's JavaScript (either on the parent page, page 0, or in your global JavaScript file):</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">customEvent</span>(<span class="hljs-params">event, data</span>) </span>{
    apex.event.trigger(<span class="hljs-built_in">document</span>, event, data);
}
</code></pre>
<ol start="2">
<li>In the modal dialog page attributes, navigate to the "Dialog" section and set the "Attributes" property to:</li>
</ol>
<pre><code class="lang-javascript">close: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ 
    customEvent(<span class="hljs-string">'customDialogClose'</span>, {<span class="hljs-attr">modalPageId</span>: <span class="hljs-string">'MODAL_CLOSE_FIXED'</span>});
}
</code></pre>
<p>This overrides the default close behavior and triggers a custom event named "customDialogClose" when the dialog is closed, including when the "X" button is clicked</p>
<h2 id="heading-creating-a-dynamic-action-on-the-parent-page"><strong>Creating a Dynamic Action on the Parent Page</strong></h2>
<ol start="3">
<li>On the parent page, create a new dynamic action with the following settings:</li>
</ol>
<ul>
<li><p>Event: Custom</p>
</li>
<li><p>Custom Event: customDialogClose</p>
</li>
<li><p>Selection Type: JavaScript Expression</p>
</li>
<li><p>JavaScript Expression: document</p>
</li>
</ul>
<ol start="4">
<li>Add the desired actions to this dynamic action, such as refreshing regions, setting item values, or executing JavaScript code</li>
</ol>
<h2 id="heading-additional-considerations"><strong>Additional Considerations</strong></h2>
<ul>
<li><p>This approach will handle both the "X" button click and other cancellation methods, such as using a dynamic action with a "Cancel Dialog" action.</p>
</li>
<li><p>The custom event will be triggered on the parent page, allowing you to perform actions after the dialog is closed.</p>
</li>
<li><p>You can use the data attribute (modalPageId in the example) to differentiate between multiple modal dialogs if needed.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[QR CODE enchancements]]></title><description><![CDATA[The APEX QR Code page item is very useful, but I miss the option to download it as an image and let users change the QR Code size. Currently, only a developer can edit the item to change its size.
First, we need to create a QR CODE item. In my exampl...]]></description><link>https://apexblog.dev/qr-code-enchancements</link><guid isPermaLink="true">https://apexblog.dev/qr-code-enchancements</guid><category><![CDATA[Apex]]></category><category><![CDATA[#oracle-apex]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Sun, 01 Dec 2024 08:00:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732887571396/05431fc0-7259-4d95-b3ae-2b778fc2821a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>The APEX QR Code page item is very useful, but I miss the option to download it as an image and let users change the QR Code size. Currently, only a developer can edit the item to change its size.</strong></p>
<p>First, we need to create a QR CODE item. In my example, the item is called P2_QRCODE, with the static value of www.apexblog.dev. When we point the camera at it, it will open the browser and go to this blog.</p>
<h2 id="heading-download-the-qr-code">Download the QR Code</h2>
<p>To enable downloading the QR Code as an image, I will use a bit of JavaScript to capture a screenshot of the item and save it as a JPG. I am currently hardcoding the image filename, but we can also add a new parameter to the function to make it dynamic.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">downloadQrcode</span>(<span class="hljs-params">item</span>) </span>{
<span class="hljs-keyword">var</span> svgElement = apex.item(item).node.querySelector(<span class="hljs-string">"svg"</span>),
    itemElement = apex.item(item);
    <span class="hljs-keyword">if</span> (!svgElement) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Invalid QRCODE"</span>);
    }
    <span class="hljs-keyword">var</span> svgString = <span class="hljs-keyword">new</span> XMLSerializer().serializeToString(svgElement);
    <span class="hljs-comment">// set larger canvas dimensions</span>
    <span class="hljs-keyword">var</span> canvas = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'canvas'</span>);
    canvas.width = itemElement.offsetWidth;
    canvas.height = itemElement.offsetHeight;
    <span class="hljs-keyword">var</span> ctx = canvas.getContext(<span class="hljs-string">"2d"</span>);

    <span class="hljs-comment">// clear background</span>
    ctx.fillStyle = <span class="hljs-string">"#ffffff"</span>;
    ctx.fillRect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, canvas.width, canvas.height);

    <span class="hljs-keyword">var</span> DOMURL = self.URL || self.webkitURL || self;
    <span class="hljs-keyword">var</span> img = <span class="hljs-keyword">new</span> Image();
    <span class="hljs-keyword">var</span> svgBlob = <span class="hljs-keyword">new</span> Blob([svgString], {<span class="hljs-attr">type</span>: <span class="hljs-string">"image/svg+xml;charset=utf-8"</span>});
    <span class="hljs-keyword">var</span> url = DOMURL.createObjectURL(svgBlob);

    img.onload = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-comment">// calculate scaling to fit the entire QR code</span>
        <span class="hljs-keyword">var</span> scale = <span class="hljs-built_in">Math</span>.min(canvas.width / img.width, canvas.height / img.height);
        <span class="hljs-keyword">var</span> x = (canvas.width - img.width * scale) / <span class="hljs-number">2</span>;
        <span class="hljs-keyword">var</span> y = (canvas.height - img.height * scale) / <span class="hljs-number">2</span>;

        <span class="hljs-comment">// draw the image centered and scaled</span>
        ctx.drawImage(img, x, y, img.width * scale, img.height * scale);
        <span class="hljs-comment">// Create an image element and download it</span>
        <span class="hljs-keyword">var</span> jpg = canvas.toDataURL(<span class="hljs-string">'image/jpeg'</span>, <span class="hljs-number">1.0</span>);
        <span class="hljs-keyword">var</span> link = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"a"</span>);
        <span class="hljs-built_in">document</span>.body.appendChild(link);
        link.href = jpg;
        link.download = <span class="hljs-string">'qrcode.jpg'</span>;
        link.click();
        <span class="hljs-built_in">document</span>.body.removeChild(link);
        DOMURL.revokeObjectURL(url);
    };

    img.src = url;
}
</code></pre>
<p>We can now copy and paste this function into the page's Function and Global Variable Declaration section or add it to a JavaScript file, as long as it is accessible on the page.</p>
<p>The next step is to create a button and a dynamic action that triggers when we click the button. Add an action to this dynamic action of type Execute JavaScript Code and include the code below.</p>
<pre><code class="lang-javascript">downloadQrcode(<span class="hljs-string">"P2_QR_CODE"</span>);
</code></pre>
<p>When we click the button, the qrcode.jpg file is downloaded.</p>
<h2 id="heading-change-qr-code-size">Change QR Code Size</h2>
<p>If we inspect the QR Code using the browser's developer tools, we will notice that each size has a different CSS class.</p>
<ul>
<li><p>small: a-QRCode--sm</p>
</li>
<li><p>medium: a-QRCode--md</p>
</li>
<li><p>large: a-QRCode--lg</p>
</li>
</ul>
<p>By changing the class, the size will also change. To manage this, let's do the following:</p>
<ol>
<li><p>Create a Radio Group with the following static values</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732886818300/ef5cdc94-ab77-4682-bbd1-3d04b582709c.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Create an on-change dynamic action to trigger when you click on the radio group item.</p>
</li>
<li><p>Add an Execute JavaScript Code action with the code below. This JavaScript code will get the chosen value from the Radio Group and change the QR CODE item's class accordingly.  </p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">var</span> elementId = <span class="hljs-built_in">this</span>.affectedElements[<span class="hljs-number">0</span>].id
 size = apex.item(<span class="hljs-built_in">this</span>.triggeringElement.id).getValue();

 <span class="hljs-keyword">if</span> (size == <span class="hljs-string">'S'</span>){
     apex.item(elementId).node.className = <span class="hljs-string">"a-QRCode a-QRCode--sm"</span>;
 }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (size == <span class="hljs-string">'M'</span>){
     apex.item(elementId).node.className = <span class="hljs-string">"a-QRCode a-QRCode--md"</span>;
 }<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (size == <span class="hljs-string">'L'</span>){
     apex.item(elementId).node.className = <span class="hljs-string">"a-QRCode a-QRCode--lg"</span>;
 }
</code></pre>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Managing CSS/JS cache in Oracle APEX]]></title><description><![CDATA[APEX provides capabilities to include custom JavaScript and CSS to enhance the look and functionality of your web applications. By implementing these scripts and styles at the application level, you ensure consistency and reusability across all pages...]]></description><link>https://apexblog.dev/managing-cssjs-cache-in-oracle-apex</link><guid isPermaLink="true">https://apexblog.dev/managing-cssjs-cache-in-oracle-apex</guid><category><![CDATA[CSS]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Apex]]></category><category><![CDATA[#oracle-apex]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Fri, 26 Jul 2024 16:15:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1722010398253/3d993835-39d5-40c9-ae75-04b5ba976717.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>APEX provides capabilities to include custom JavaScript and CSS to enhance the look and functionality of your web applications. By implementing these scripts and styles at the application level, you ensure consistency and reusability across all pages. This guide will walk you through the process of integrating JavaScript and CSS at the application level in Oracle APEX.</p>
<h1 id="heading-saving-the-cssjs-file">Saving the css/js file</h1>
<h4 id="heading-upload-the-javascript-file-to-apex-static-files">Upload the JavaScript File to APEX Static Files</h4>
<ol>
<li><p><strong>Navigate to Shared Components</strong>:</p>
<ul>
<li><p>From the Application Builder, select the application you want to add the JS/CSS file to.</p>
</li>
<li><p>Click on <strong>Shared Components</strong> in the application menu.</p>
</li>
<li><p>Under the <strong>Files and Reports</strong> section, click on <strong>Static Application Files</strong>.</p>
</li>
</ul>
</li>
<li><p><strong>Upload/Create the File</strong>:</p>
<ul>
<li><p>Click on the <strong>Create File</strong> button.</p>
</li>
<li><p>Choose the file from your local machine or click on create to open the editor</p>
</li>
<li><p>Optionally, you can create a directory to keep your files organized. For example, you might create a directory called <code>js</code> and upload the javascript files into this directory.</p>
</li>
<li><p>Click <strong>Create</strong> to add the file to your application’s static files.  </p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722008284595/9a051ba8-dace-4e32-ae94-e5dda351e51e.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
</ol>
<h1 id="heading-reference-the-javascript-file-in-your-application">Reference the JavaScript File in Your Application</h1>
<p>After uploading the file, you need to reference it in your application so it can be utilized across various pages.  </p>
<p>In this example, I created the app.js JavaScript file, and APEX automatically created the minified version of this file. We should also use the minified version to reduce memory usage and loading time.  </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722008590014/d2ac7e51-b1c8-4f44-9164-fff6cb0e03d8.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p><strong>Navigate to User Interface Attributes</strong>:</p>
<ul>
<li><p>From the Application Builder, click on <strong>Shared Components</strong>.</p>
</li>
<li><p>Under the <strong>User Interface</strong> section, click on <strong>JavaScript</strong> or <strong>CSS</strong> depending on your file type.</p>
</li>
</ul>
</li>
</ol>
<p>Add the file path pointing to the file we just created.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722008938126/0f302c42-640d-4b09-8bf8-c69325dc6f4d.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-check-if-the-file-is-loaded">Check if the file is loaded</h1>
<ul>
<li><p><strong>Run the Application</strong>:</p>
<ul>
<li><p>Add the following code to the app.js file</p>
<pre><code class="lang-javascript">  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'app.js loaded successfully!'</span>);
</code></pre>
</li>
<li><p>Run your application.</p>
</li>
<li><p>Open the browser’s Developer Tools (usually accessed by pressing <code>F12</code>) and check the Console and you chould see the message <em>app.js loaded successfully!</em></p>
</li>
</ul>
</li>
</ul>
<h1 id="heading-using-version-control">Using version control</h1>
<p>When we don't use version control, after a change to <code>app.js</code>, the browser can cache the file and the changes won't be available when running the app. Users will need to manually clear the cache. To avoid that, use version control. Every time you make changes to the app and release it, the browsers will be forced to refresh the cached file when running the app.  </p>
<p>Version control for static files in APEX is implemented by appending <code>?version=#APP_VERSION#</code> to file URLs, ensuring users always receive the latest versions of CSS and JavaScript files without manual cache clearing.  </p>
<p>When setting the file URL instead of  </p>
<pre><code class="lang-java">#APP_FILES#js/app#MIN#.js
</code></pre>
<p>we should use</p>
<pre><code class="lang-java">#APP_FILES#js/app#MIN#.js?version=#APP_VERSION#
</code></pre>
]]></content:encoded></item><item><title><![CDATA[JSON inside Oracle Database]]></title><description><![CDATA[JSON (JavaScript Object Notation) is a lightweight data-interchange format primarily for transferring data between systems. In most cases, we parse the JSON object to store the values in relational tables but we can also store the JSON object in a si...]]></description><link>https://apexblog.dev/json-inside-oracle-database</link><guid isPermaLink="true">https://apexblog.dev/json-inside-oracle-database</guid><category><![CDATA[JSON Datatype]]></category><category><![CDATA[Oracle]]></category><category><![CDATA[json]]></category><category><![CDATA[PL/SQL]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Tue, 11 Jun 2024 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1669850775463/D34_LHgNY.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>JSON (JavaScript Object Notation) is a lightweight data-interchange format primarily for transferring data between systems. In most cases, we parse the JSON object to store the values in relational tables but we can also store the JSON object in a single table column and extract the data using SQL.</p>
<p>In my use case below, using a public API (<a target="_blank" href="https://postcodes.io">https://postcodes.io</a>), I will extract and save the data related to a postcode.</p>
<p>To begin, we need to create a table column to store the JSON Document this could be either:</p>
<ul>
<li><p>JSON datatype - Oracle 21c Database</p>
</li>
<li><p>VARCHAR2 - small documents</p>
</li>
<li><p>CLOB</p>
</li>
<li><p>BLOB</p>
</li>
</ul>
<p>For Oracle 21c users, JSON datatype is the best option; however, for other database versions, the best option is to use a BLOB column, as it stores the exact JSON document without any character set conversions, resulting in less storage in most cases. VARCHAR2 is only recommended when we can ensure that the JSON document won't exceed the maximum size of 32767.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> location (
    <span class="hljs-keyword">id</span>                 <span class="hljs-built_in">number</span> <span class="hljs-keyword">generated</span> <span class="hljs-keyword">by</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">on</span> <span class="hljs-literal">null</span> <span class="hljs-keyword">as</span> <span class="hljs-keyword">identity</span> 
                          <span class="hljs-keyword">constraint</span> location_id_pk primary <span class="hljs-keyword">key</span>,
    postcode              <span class="hljs-built_in">varchar2</span>(<span class="hljs-number">10</span>),                               
    postcode_json_content <span class="hljs-built_in">blob</span>
);
</code></pre>
<p>and a trigger calling the API and save the request as a blob.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">replace</span> <span class="hljs-keyword">trigger</span> <span class="hljs-string">"BI_LOCATION"</span>   
 <span class="hljs-keyword">before</span> <span class="hljs-keyword">insert</span> <span class="hljs-keyword">on</span> <span class="hljs-string">"LOCATION"</span>               
 <span class="hljs-keyword">for</span> <span class="hljs-keyword">each</span> <span class="hljs-keyword">row</span>  
<span class="hljs-keyword">declare</span>  
 l_json_postcode <span class="hljs-built_in">blob</span>;
<span class="hljs-keyword">begin</span>   
     l_json_postcode := apex_web_service.make_rest_request_b(
       p_url =&gt; <span class="hljs-string">'https://api.postcodes.io/postcodes/'</span>||:new.postcode,
       p_http_method =&gt; <span class="hljs-string">'GET'</span>);
       :NEW.postcode_json_content := l_json_postcode;
<span class="hljs-keyword">end</span>;
</code></pre>
<p>If we insert any valid postcode at this point, the trigger will call the API and save the blob content, but it is only a blob content. If we try to save an image in postcode_json_content, that will work because there is nothing to prevent only JSON valid data. To solve that, we add a constraint as follows.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">alter</span> <span class="hljs-keyword">table</span> LOCATION
 <span class="hljs-keyword">add</span> <span class="hljs-keyword">constraint</span> postcode_data_json 
 <span class="hljs-keyword">check</span> ( postcode_json_content <span class="hljs-keyword">is</span> <span class="hljs-keyword">json</span> );
</code></pre>
<p>The column postcode_json_content now only accepts valid JSON objects. Now we can add some data.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> location(postcode) <span class="hljs-keyword">values</span> (<span class="hljs-string">'SW1A1AA'</span>);
</code></pre>
<p>If a valid JSON is returned from the API, we have the following</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> to_clob(postcode_json_content) postcode_json_content <span class="hljs-keyword">from</span> location;

{
    "status": 200,
    "result": {
        "postcode": "SW1A 1AA",
        "quality": 1,
        "eastings": 529090,
        "northings": 179645,
        "country": "England",
        "nhs_ha": "London",
        "longitude": -0.141588,
        "latitude": 51.501009,
        "european_electoral_region": "London",
        "primary_care_trust": "Westminster",
        "region": "London",
        "lsoa": "Westminster 018C",
        "msoa": "Westminster 018",
        "incode": "1AA",
        "outcode": "SW1A",
        "parliamentary_constituency": "Cities of London and Westminster",
        "admin_district": "Westminster",
        "parish": "Westminster, unparished area",
        "admin_county": null,
        "admin_ward": "St James's",
        "ced": null,
        "ccg": "NHS North West London",
        "nuts": "Westminster",
        "codes": {
            "admin_district": "E09000033",
            "admin_county": "E99999999",
            "admin_ward": "E05000644",
            "parish": "E43000236",
            "parliamentary_constituency": "E14000639",
            "ccg": "E38000256",
            "ccg_id": "W2U3Z",
            "ced": "E99999999",
            "nuts": "TLI32",
            "lsoa": "E01004736",
            "msoa": "E02000977",
            "lau2": "E09000033"
        }
    }
}
</code></pre>
<p>Now we can easily extract the data and specify the correct data type to be returned.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> l.postcode_json_content.result.latitude.number() <span class="hljs-keyword">as</span> latitude,
        l.postcode_json_content.result.longitude.number() <span class="hljs-keyword">as</span> longitude,
        l.postcode_json_content.result.region.string() <span class="hljs-keyword">as</span> region,
        l.postcode_json_content.result.country.string() <span class="hljs-keyword">as</span> country,
        l.postcode_json_content.result.parish.string() <span class="hljs-keyword">as</span> longitude
   <span class="hljs-keyword">from</span> location l
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669850460386/Mms1BTOFm.png" alt class="image--center mx-auto" /></p>
<p><strong>Important!</strong> We need to prefix the columns alias to avoid the error below.</p>
<p>ORA-00904: "POSTCODE_JSON_CONTENT"."RESULT"."LONGITUDE": invalid identifier</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX Template Component Plugin Stats Counter]]></title><description><![CDATA[Meet the Stats Counter, a new APEX item plugin designed to add some nice stats to your page.

Installation

Download Stats Counter

Import template_component_plugin_com_rodrigomesquita_statscounter.sql file into your application.


Usage

Create a pa...]]></description><link>https://apexblog.dev/oracle-apex-template-component-plugin-stats-counter</link><guid isPermaLink="true">https://apexblog.dev/oracle-apex-template-component-plugin-stats-counter</guid><category><![CDATA[#oracle-apex]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Mon, 27 May 2024 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1716917351562/1861868f-9f35-45f4-8932-0260a8698744.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Meet the Stats Counter, a new APEX item plugin designed to add some nice stats to your page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716916020455/5dbc8e56-551a-43fe-8c37-045f96c1b6fa.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-installation">Installation</h2>
<ol>
<li><p>Download <a target="_blank" href="https://github.com/rodrigomesquitaorclapex/stats-counter/tree/main"><strong>Stats Counter</strong></a></p>
</li>
<li><p>Import template_component_plugin_com_rodrigomesquita_statscounter.sql file into your application.</p>
</li>
</ol>
<h2 id="heading-usage">Usage</h2>
<ol>
<li><p>Create a page item</p>
</li>
<li><p>Choose <em>Stats Counter [Plugin]</em> as an item type</p>
</li>
</ol>
<h2 id="heading-responsive-and-perfect-for-all-screens">Responsive and perfect for all screens</h2>
<p>When using small screens, the layout adjusts to a more attractive view.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716916974137/6cc49d7f-10d6-437e-853c-289ed55932b2.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-adapt-to-any-theme-style">Adapt to any theme style</h2>
<p>Don't worry if your user prefers dark mode; it will look awesome too.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716917199545/e5676743-d68c-4412-a003-985ddf44b84b.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-demo">Demo</h2>
<p>Clique <a target="_blank" href="https://apex.oracle.com/pls/apex/r/rodrigo_sandbox/stats-counter-plugin/home"><strong>here</strong></a> so see it working.</p>
]]></content:encoded></item><item><title><![CDATA[Nested Template Components]]></title><description><![CDATA[Oracle APEX allows us to call a template component plugin inside another plugin, saving us time by reusing functionalities from another plugin without the need to rewrite them.
To show how it works, I will use the vertical timeline TC plugin. To lear...]]></description><link>https://apexblog.dev/nested-template-components</link><guid isPermaLink="true">https://apexblog.dev/nested-template-components</guid><category><![CDATA[Apex]]></category><category><![CDATA[#oracle-apex]]></category><category><![CDATA[template]]></category><category><![CDATA[HTML5]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Thu, 23 May 2024 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/n8cbM4tBALs/upload/447806e4107769f0652c3e5c89f7df16.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Oracle APEX allows us to call a template component plugin inside another plugin, saving us time by reusing functionalities from another plugin without the need to rewrite them.</p>
<p>To show how it works, I will use the vertical timeline TC plugin. To learn more about this plugin, click <a target="_blank" href="https://apexblog.dev/apex-template-components-and-10-lines-of-html-to-create-a-plugin">here</a>.</p>
<p>In this demo, the plugin is used to display the timeline of a shopping order.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716899744831/03e4d171-74e1-440a-8f75-470f2d88c97a.png" alt class="image--center mx-auto" /></p>
<p>We want to highlight when the order is canceled or delivered. For this, we are going to call the Badge plugin inside the Vertical Timeline. To call a plugin, we use the 'with/apply' template directive. This is explained in the blog post <a target="_blank" href="https://apexblog.dev/the-power-of-apex-template-directives">The Power of APEX Template Directives</a>.</p>
<p>We first need to identify where is the text that we want to change:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716901188340/d1b5efb3-b0a9-476c-8927-50d36f6de575.png" alt class="image--center mx-auto" /></p>
<p>We now know that the text we want to change comes from the description. By looking at the plugin custom attributes, we can see that the description is identified by VT_DESC  </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716901447266/ca0bdd4a-350e-49da-9e9c-3419fd0e727d.png" alt class="image--center mx-auto" /></p>
<p>Looking at the code, we can now easily identify where we need to make a change and call the bagde plugin  </p>
<p><strong>&lt;div class="vt-item-text"&gt;#VT_DESC#&lt;/div&gt;</strong></p>
<pre><code class="lang-xml">{if APEX$IS_LAZY_LOADING/}
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa fa-refresh fa-2x fa-anim-spin"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{else/}
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa #VT_ICON# vt-icon"</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vt-header"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vt_header_text"</span>&gt;</span>#VT_TEXT#<span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> #VT_SUBTEXT#<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{if APEX$HAS_ACTION_BUTTONS/} #MENU_ACTION# {endif/}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vt-item-text"</span>&gt;</span>#VT_DESC#<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{endif/}
</code></pre>
<p>The code will then be changed by adding the with/apply for the <em>Order Canceled</em> (using danger state) and <em>The order has been delivered</em> (using success state).</p>
<pre><code class="lang-xml">{if APEX$IS_LAZY_LOADING/}
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa fa-refresh fa-2x fa-anim-spin"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{else/}
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa #VT_ICON# vt-icon"</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vt-header"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vt_header_text"</span>&gt;</span>#VT_TEXT#<span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> #VT_SUBTEXT#<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{if APEX$HAS_ACTION_BUTTONS/} #MENU_ACTION# {endif/}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
           {case VT_DESC/}
       {when Order Canceled/}
            {with/}
            LABEL:=
            VALUE:=#VT_DESC#
            STATE:=danger
            ICON:=fa-times-circle-o
            LABEL_DISPLAY:=N
            STYLE:=t-Badge--md
            SHAPE:=t-Badge--circle
            {apply THEME$BADGE/}  
        {when The order has been delivered/}
            {with/}
            LABEL:=
            VALUE:=#VT_DESC#
            STATE:=success
            ICON:=fa-times-circle-o
            LABEL_DISPLAY:=N
            STYLE:=t-Badge--md
            SHAPE:=t-Badge--circle
            {apply THEME$BADGE/}                     
       {otherwise/}
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vt-item-text"</span>&gt;</span>#VT_DESC#<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {endcase/}
{endif/}
</code></pre>
<p>and finally we have the below:  </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716902051507/4ff9771c-4a91-4d90-a8e4-b02d1e513b9b.png" alt class="image--center mx-auto" /></p>
<p>and</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716902070527/cc72a9e6-f30d-4cf4-939c-001320ddef74.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[The Power of APEX Template Directives]]></title><description><![CDATA[Oracle APEX Template Directives allow us to move data formatting from SQL to HTML, creating easier-to-read queries, improving performance, and reducing the risk of Cross-Site Scripting attacks.  
Template Components can be used on any component with ...]]></description><link>https://apexblog.dev/the-power-of-apex-template-directives</link><guid isPermaLink="true">https://apexblog.dev/the-power-of-apex-template-directives</guid><category><![CDATA[template components]]></category><category><![CDATA[Apex]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Sun, 31 Mar 2024 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1716888301585/b58e8431-0043-48d3-aa50-2eebd3d6983f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Oracle APEX Template Directives allow us to move data formatting from SQL to HTML, creating easier-to-read queries, improving performance, and reducing the risk of Cross-Site Scripting attacks.  </p>
<p>Template Components can be used on any component with the HTML Expression, and we have the following options:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716886477229/611d5d8f-8915-4bf0-bfc9-e9e292c2f941.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p>IF: For the IF example we are going to use the DISABLE_FLAG column. If there the column is not null will return Yes else NO.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716886752184/b2fbfe23-aaf7-462f-93bd-7c65edb949ea.png" alt class="image--center mx-auto" /></p>
<p> Token Modifiers</p>
<p> | Condition | Directive |
 | --- | --- |
 | if_exists_and_true | <code>{if ITEM/}</code> |
 | if_exists | <code>{if ?ITEM/}</code> |
 | if_not_exists_or_false | <code>{if !ITEM/}</code> |
 | if_not_exists | <code>{if !?ITEM/}</code> |
 | if_not_false | <code>{if =ITEM/}</code> |
 | if_exists_and_false | <code>{if !=ITEM/}</code> |</p>
</li>
<li><p>CASE: For the CASE we are going to use the GENDER column. When M we will show the fa-male icon and fa-female when the value is F.  </p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716887037779/30314170-0440-47f3-ab8c-d8cf3b44c45b.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>LOOP: For the LOOP, the column BADGES contains colon-separated values representing all the badges the user has. We are going to break that into &lt;li&gt; elements and add the fa-trophy icon.  </p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716887238995/70672e42-af74-4d16-a30a-c50f665724a5.png" alt class="image--center mx-auto" /></p>
<p> The code above will return the following:</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716887355360/7252c855-fa64-4409-bf19-07dbc1553d0c.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>WITH and APPLY allow us to add predefined template component plugins and use them inside a template component (nested template component) or in HTML Expressions. In the example below, we will use the BADGE template component plugin to show the value of the FULL_NAME column.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716887638549/a4a84d4f-d100-40e2-b25c-c996531d0dff.png" alt class="image--center mx-auto" /></p>
<p> The code above will return the following:</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716887681852/d363a591-383c-420d-a570-e8d582e857d7.png" alt class="image--center mx-auto" /></p>
<p> To help us build the WITH/APPLY and add all the custom attributes for each plugin, <a class="user-mention" href="https://hashnode.com/@lufcmattylad">Matt Mulvaney</a> created the <a target="_blank" href="https://apex.oracle.com/pls/apex/r/luf/with-apply-generator/home">Template Component With/Apply Generator</a> This tool is very helpful for generating the WITH/APPLY for each plugin</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716888016057/2c96c11c-9c14-48be-9981-8a9987cca956.png" alt class="image--center mx-auto" /></p>
<p> ##</p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[APEX Template Components and 10 lines of HTML to create a plugin]]></title><description><![CDATA[One of the fantastic aspects of template component plugins is that there's no need to delve into complex APIs to develop a plugin. If you have a bit of understanding of HTML and CSS, you can swiftly create impressive plugins.
Introducing the Vertical...]]></description><link>https://apexblog.dev/apex-template-components-and-10-lines-of-html-to-create-a-plugin</link><guid isPermaLink="true">https://apexblog.dev/apex-template-components-and-10-lines-of-html-to-create-a-plugin</guid><category><![CDATA[#oracle-apex]]></category><category><![CDATA[Oracle]]></category><category><![CDATA[CSS]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[Low Code]]></category><dc:creator><![CDATA[Rodrigo Mesquita]]></dc:creator><pubDate>Thu, 02 Nov 2023 23:06:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1698966254499/6fb2c876-fe46-4e5d-957d-4f4bab4b7cde.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One of the fantastic aspects of template component plugins is that there's no need to delve into complex APIs to develop a plugin. If you have a bit of understanding of HTML and CSS, you can swiftly create impressive plugins.</p>
<p>Introducing the Vertical Timeline: Witness how a plugin can be created with minimal code in no time.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698965016372/aea81322-ffc5-42e2-a659-0e1d664eb6c8.png" alt class="image--center mx-auto" /></p>
<p>Looks pretty cool, and it's all done with just 10 lines of HTML and a touch of CSS.  </p>
<pre><code class="lang-xml">{if APEX$IS_LAZY_LOADING/}
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa fa-refresh fa-2x fa-anim-spin"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{else/}
    <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"fa #VT_ICON# vt-icon"</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vt-header"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vt_header_text"</span>&gt;</span>#VT_TEXT#<span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> #VT_SUBTEXT#<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{if APEX$HAS_ACTION_BUTTONS/} #MENU_ACTION# {endif/}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
       <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"vt-item-text"</span>&gt;</span>#VT_DESC#<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
{endif/}
</code></pre>
<p>Additionally, it comes with an action menu. In the demo, I've set up five menu items, each with its own server-side condition to show selectively on specific timeline entries, based on the flag column in the query below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698965391528/925860e4-d61c-4109-a0e6-0c6a0c5e62d8.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-sample-query"><strong>Sample Query</strong></h2>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span>
  <span class="hljs-string">'Order Received'</span> <span class="hljs-keyword">AS</span> event_text,
  <span class="hljs-string">'01-AUG-2023'</span> <span class="hljs-keyword">AS</span> event_date,
  <span class="hljs-string">'9:00 AM'</span>  <span class="hljs-keyword">as</span> event_time,
  <span class="hljs-string">'fa-shopping-cart'</span> <span class="hljs-keyword">as</span> card_icon,
  <span class="hljs-string">'Y'</span> edit_flag,
  <span class="hljs-string">'Y'</span> cancel_flag,
  <span class="hljs-string">'N'</span> track_flag,
  <span class="hljs-string">'N'</span> review_flag,
  <span class="hljs-string">'N'</span> return_flag
<span class="hljs-keyword">FROM</span> DUAL
<span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span>
<span class="hljs-keyword">SELECT</span>
  <span class="hljs-string">'Order is being processed in our warehouse'</span> <span class="hljs-keyword">AS</span> event_text,
  <span class="hljs-string">'02-AUG-2023'</span> <span class="hljs-keyword">as</span> event_date,
  <span class="hljs-string">'10:00 AM'</span>  <span class="hljs-keyword">as</span> event_time,
  <span class="hljs-string">'fa-package'</span> <span class="hljs-keyword">as</span> card_icon,
  <span class="hljs-string">'N'</span> edit_flag,
  <span class="hljs-string">'Y'</span> cancel_flag,
  <span class="hljs-string">'N'</span> track_flag,
  <span class="hljs-string">'N'</span> review_flag,
  <span class="hljs-string">'N'</span> return_flag
<span class="hljs-keyword">FROM</span> DUAL
<span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span>
<span class="hljs-keyword">SELECT</span>
  <span class="hljs-string">'Your order is shipped'</span> <span class="hljs-keyword">AS</span> event_text,
  <span class="hljs-string">'02-AUG-2023'</span> <span class="hljs-keyword">as</span> event_date,
  <span class="hljs-string">'1:00 PM'</span> <span class="hljs-keyword">as</span> event_time,
  <span class="hljs-string">'fa-plane'</span> <span class="hljs-keyword">as</span> card_icon,
  <span class="hljs-string">'N'</span> edit_flag,
  <span class="hljs-string">'N'</span> cancel_flag,
  <span class="hljs-string">'Y'</span> track_flag,
  <span class="hljs-string">'N'</span> review_flag,
  <span class="hljs-string">'N'</span> return_flag
<span class="hljs-keyword">FROM</span> DUAL
<span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span>
<span class="hljs-keyword">SELECT</span>
  <span class="hljs-string">'Your order has arrived in Leeds - UK'</span> <span class="hljs-keyword">AS</span> event_text,
  <span class="hljs-string">'03-AUG-2023'</span> <span class="hljs-keyword">as</span> event_date,
  <span class="hljs-string">'2:00 PM'</span> <span class="hljs-keyword">as</span> event_time,
  <span class="hljs-string">'fa-map-marker-o'</span> <span class="hljs-keyword">as</span> card_icon,
  <span class="hljs-string">'N'</span> edit_flag,
  <span class="hljs-string">'N'</span> cancel_flag,
  <span class="hljs-string">'Y'</span> track_flag,
  <span class="hljs-string">'N'</span> review_flag,
  <span class="hljs-string">'N'</span> return_flag
<span class="hljs-keyword">FROM</span> DUAL
<span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span>
<span class="hljs-keyword">SELECT</span>
  <span class="hljs-string">'Your order has been pickup by the driver'</span> <span class="hljs-keyword">AS</span> event_text,
  <span class="hljs-string">'03-AUG-2023'</span> <span class="hljs-keyword">as</span> event_date,
  <span class="hljs-string">'03:00 PM'</span> <span class="hljs-keyword">as</span> event_time,
  <span class="hljs-string">'fa-truck'</span> <span class="hljs-keyword">as</span> card_icon,
  <span class="hljs-string">'N'</span> edit_flag,
  <span class="hljs-string">'N'</span> cancel_flag,
  <span class="hljs-string">'Y'</span> track_flag,
  <span class="hljs-string">'N'</span> review_flag,
  <span class="hljs-string">'N'</span> return_flag
<span class="hljs-keyword">FROM</span> DUAL
<span class="hljs-keyword">UNION</span> <span class="hljs-keyword">ALL</span>
<span class="hljs-keyword">SELECT</span>
  <span class="hljs-string">'The order has been delivered'</span> <span class="hljs-keyword">AS</span> event_text,
  <span class="hljs-string">'03-AUG-2023'</span> <span class="hljs-keyword">as</span> event_date,
  <span class="hljs-string">'06:00 PM'</span> <span class="hljs-keyword">as</span> event_time,
  <span class="hljs-string">'fa-home'</span> <span class="hljs-keyword">as</span> card_icon,
  <span class="hljs-string">'N'</span> edit_flag,
  <span class="hljs-string">'N'</span> cancel_flag,
  <span class="hljs-string">'N'</span> track_flag,
  <span class="hljs-string">'Y'</span> review_flag,
  <span class="hljs-string">'Y'</span> return_flag
<span class="hljs-keyword">FROM</span> DUAL
</code></pre>
<h2 id="heading-installation"><strong>Installation</strong></h2>
<ol>
<li><p>Download <a target="_blank" href="https://github.com/rodrigomesquitaorclapex/verticalTimeline"><strong>Vertical Timeline</strong></a></p>
</li>
<li><p>Import <em>template_component_plugin_com_rodrigomesquita_vertical_timeline.sql</em>file into your application.</p>
</li>
</ol>
<h2 id="heading-usage"><strong>Usage</strong></h2>
<ol>
<li><p>Create a page item</p>
</li>
<li><p>Choose <em>Vertical Timeline [Plugin]</em> as a template component type</p>
</li>
</ol>
<h2 id="heading-configuration"><strong>Configuration</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1698965831672/c1fe419d-8c97-4ac7-a6d5-bded44b8388e.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-demo"><strong>Demo</strong></h2>
<p>Clique <a target="_blank" href="https://apex.oracle.com/pls/apex/r/rodrigo_sandbox/vertical-timeline/home"><strong>here</strong></a> to see in action.</p>
]]></content:encoded></item></channel></rss>