<?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[Lucas Hirschegger]]></title><description><![CDATA[Lucas Hirschegger]]></description><link>https://blog.lucashir.eu</link><generator>RSS for Node</generator><lastBuildDate>Fri, 10 Apr 2026 17:35:17 GMT</lastBuildDate><atom:link href="https://blog.lucashir.eu/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Oracle APEX – The Standard Component Attributes Anatomy Series: Audit Information]]></title><description><![CDATA[Audit Information
The Audit section captures key metadata about each component in your APEX application. Specifically, it records:

Changed By: The username of the last developer who modified the component.

Changed On: The timestamp of the last modi...]]></description><link>https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-audit-information</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-audit-information</guid><category><![CDATA[orclapex]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Tue, 02 Sep 2025 18:52:49 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-audit-information">Audit Information</h2>
<p>The <strong>Audit</strong> section captures key metadata about each component in your APEX application. Specifically, it records:</p>
<ul>
<li><p><strong>Changed By</strong>: The username of the last developer who modified the component.</p>
</li>
<li><p><strong>Changed On</strong>: The timestamp of the last modification.</p>
</li>
</ul>
<p>This information is <strong>automatically tracked by APEX</strong> and displayed as read-only fields within Page Designer and other areas of the Application Builder. Like most metadata in APEX, these audit details are also available through the APEX dictionary views.</p>
<p>When exporting an application, you can choose whether or not to include audit metadata. This is especially important if you're using version control:</p>
<ul>
<li><p><strong>Excluding audit info</strong> can reduce noise in version diffs, making it easier to track real functional changes.</p>
</li>
<li><p><strong>Including audit info</strong> might be useful in simpler setups to retain a lightweight, built-in form of change tracking.</p>
</li>
</ul>
<p>You can configure this in the <strong>Export Application</strong> dialog under the <strong>"Include Audit Information"</strong> section. Options include:</p>
<ul>
<li><p><strong>None</strong> <em>(default)</em> – No audit information is exported.</p>
</li>
<li><p><strong>Dates Only</strong> – Only timestamps (<code>Created On</code>, <code>Changed On</code>) are included.</p>
</li>
<li><p><strong>Names and Dates</strong> – Both usernames and timestamps (<code>Created By</code>, <code>Changed By</code>, etc.) are included.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753135103535/9fd12259-2037-41f8-b4ee-7790dbf9afb1.png" alt="Oracle APEX - Include audit information radio example" class="image--center mx-auto" /></p>
<p>This setting lets you strike the right balance between traceability and clean version control depending on your development workflow.</p>
<p>Enjoy life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX – The Standard Component Attributes Anatomy Series: Configuration a.k.a. Build Option]]></title><description><![CDATA[In this fifth post of The Standard Component Attributes Anatomy series, I’m focusing on the Configuration attribute—better known as Build Options. Since Build Options are managed in Shared Components, we’ll take a quick look at that area as well.
Con...]]></description><link>https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-configuration-aka-build-option</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-configuration-aka-build-option</guid><category><![CDATA[orclapex]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Tue, 02 Sep 2025 18:52:31 GMT</pubDate><content:encoded><![CDATA[<p>In this fifth post of The Standard Component Attributes Anatomy series, I’m focusing on the Configuration attribute—better known as Build Options. Since Build Options are managed in Shared Components, we’ll take a quick look at that area as well.</p>
<h2 id="heading-configuration">Configuration</h2>
<p>In the configuration section, you can set the <strong>Build Option</strong> attribute—an often overlooked but powerful feature in APEX. It lets you enable or disable components or groups of components dynamically.</p>
<p>Some practical use cases from the official help include:</p>
<ol>
<li><p><strong>Multi-installation apps:</strong> Develop one app and use Build Options to tailor functionality per installation, allowing privileged users to toggle features on or off.</p>
</li>
<li><p><strong>Incomplete features:</strong> Hide unfinished functionality in test or production environments without removing the code, enabling safe deployment.</p>
</li>
<li><p><strong>Safe removal:</strong> Temporarily disable features you’re unsure about (“comment them out”) and easily restore them if needed before permanent removal.</p>
</li>
</ol>
<p>Some of these cases are built into APEX by design. For example, the <strong>“Commented Out”</strong> build option is an excluded option that lets you temporarily disable a component—useful during debugging or before deprecation. To apply a build option, simply select the desired option for the component. By default, APEX presents both the option and its negation for easy toggling.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753135927816/bac79e74-6f71-450d-8f72-794a7cfa2bd0.png" alt="Oracle APEX - Build option list in application builder" class="image--center mx-auto" /></p>
<p>A shortcut for this specific case is available in the context menu of any component in Page Designer — just right-click the component in the rendering tree to quickly set its build option.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753136451822/28262bd6-f8b6-41a1-a1ae-e56ba60531a2.png" alt="Oracle APEX - Context menu comment out option" class="image--center mx-auto" /></p>
<p>For this case, behind the scenes, APEX automatically creates the build option for you when creating an application through the wizard. If your application is from an older export, you can manually create the build option with the same name under Shared Components to gain access to that shortcut in recent versions of APEX.</p>
<p>Another example of implementing a build option is with feature pages. You might recall the built-in features that come with APEX:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755182470993/4eebd525-6594-4c64-a713-7e26905c3132.png" alt="Oracle APEX - Create a feauture page example in Application builder" class="image--center mx-auto" /></p>
<p>Most features include a build option designed to support the first use case—tailoring functionality for each installation. You can test this by enabling a specific feature and checking the results in the Build Options section of Shared Components.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755183016235/968c5036-5812-42cb-a6db-2d6d957c930e.png" alt class="image--center mx-auto" /></p>
<p>Just like with authorization schemes, before assigning a build option to a component, you first need to create and configure that build option under <strong>Build Options</strong> in the <strong>Application Logic</strong> section of Shared Components.</p>
<p>Remember, you can quickly access the Create Build Option wizard directly from Page Designer, under the Shared Components list, as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755182055980/3378f19f-8324-48aa-a915-407feda34e82.png" alt="Oracle APEX - Create build option menu from page builder, shared component view" class="image--center mx-auto" /></p>
<p>When creating it, you set its status, which controls whether the related component or process will be:</p>
<ul>
<li><p><strong>Include:</strong> Rendered or executed</p>
</li>
<li><p><strong>Exclude:</strong> Skipped and not rendered or executed</p>
</li>
</ul>
<p>You can also set two additional attributes that simplify your deployment process, especially when working with packaged applications:</p>
<ul>
<li><p><strong>Default on Export:</strong> Sets the build option’s status when the application is exported.</p>
</li>
<li><p><strong>On Upgrade Keep Status:</strong> Determines whether the build option status in the deployed application should be preserved or overwritten during an upgrade. Selecting <strong>On</strong> to keep the deployed status is useful if your application uses the <code>APEX_UTIL.SET_BUILD_OPTION_STATUS</code> API to dynamically manage build options and you want those settings to remain intact after upgrading.</p>
</li>
</ul>
<p>A particularly handy feature in APEX is the Utilization Reports, available on most Shared Components pages. In this case, you can use them to see which components are affected by a specific build option configuration.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755183193836/ec521f9a-9ac3-4853-9f92-9de1ae675f6c.png" alt="Oracle APEX - Build options utilization report in share components" class="image--center mx-auto" /></p>
<p>And once again, there are APEX Data Dictionary views that can help if you want to access this information programmatically. Here’s an example showing how to list all existing build options, which you can filter by application or workspace:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> * 
<span class="hljs-keyword">from</span> apex_application_build_options
</code></pre>
<p>Or use this example to identify all the views where build options are available:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> * <span class="hljs-keyword">from</span> apex_dictionary
<span class="hljs-keyword">where</span> column_name <span class="hljs-keyword">like</span> <span class="hljs-string">'%BUILD%'</span>
</code></pre>
<p>Enjoy life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX – The Standard Component Attributes Anatomy Series: Comments]]></title><description><![CDATA[Comments
The Comment attribute might be one of the most universally available fields in Oracle APEX. It allows developers to quickly leave notes or remarks—for themselves or for teammates—that are never shown to end users during runtime.
You'll find ...]]></description><link>https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-comments</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-comments</guid><category><![CDATA[orclapex]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Tue, 02 Sep 2025 18:52:11 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-comments">Comments</h2>
<p>The <strong>Comment</strong> attribute might be one of the most universally available fields in Oracle APEX. It allows developers to <strong>quickly leave notes or remarks</strong>—for themselves or for teammates—that are <strong>never shown to end users</strong> during runtime.</p>
<p>You'll find the Comment field at nearly every level of the application: pages, regions, items, reports, shared components, and more.</p>
<p>Unfortunately, in practice, this attribute is <strong>underused</strong>—just like code comments often are in traditional development. We've all heard the phrase <em>“the code is the documentation”</em>, but in the world of <strong>low-code</strong>, there's often not much code to speak of! 😄</p>
<p>So, the Comment attribute becomes a valuable space to capture <strong>important context</strong>, <strong>design decisions</strong>, or <strong>reminders</strong> directly where they matter most—inside the metadata.</p>
<p>Make it a habit: your future self (or teammate) will thank you.</p>
<p>Again, since these comments are stored as metadata in the APEX dictionary, you can easily access them using SQL queries. For example, if your team has a convention to mark <strong>ToDo</strong> tasks within comments, you can quickly generate a report of all outstanding action items like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span>
    application_id,
    page_id,
    item_name,
    component_comment
<span class="hljs-keyword">FROM</span>
    apex_application_page_items
<span class="hljs-keyword">WHERE</span>
    application_id = :app_id
<span class="hljs-keyword">and</span> <span class="hljs-keyword">lower</span>(component_comment) <span class="hljs-keyword">like</span> <span class="hljs-string">'%todo%'</span>;
</code></pre>
<p>Last but not least, when exporting your application, you have the option to <strong>include or exclude developer comments</strong> right from the Page Designer export settings.</p>
<p>In the export options, you’ll find <strong>“Include Developer Comments”</strong> with two choices:</p>
<ul>
<li><p><strong>On:</strong> Developer Comments are included in the application export.</p>
</li>
<li><p><strong>Off:</strong> Developer Comments are excluded from the export.</p>
</li>
</ul>
<p>This gives you control over whether your internal notes travel with your application files—helpful when sharing with others or managing version control.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753134548669/720d80b0-8f6a-49aa-9a14-68ee9e3aa97d.png" alt="Oracle APEX - Include developer comments switch screenshot" class="image--center mx-auto" /></p>
<p>Enjoy life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX – The Standard Component Attributes Anatomy Series: Help]]></title><description><![CDATA[In this fourth post of The Standard Component Attributes Anatomy Series, we’re diving deep into the Help standard attribute.
Although often overlooked, the Help attribute plays an important role in improving the user experience by providing clear, co...]]></description><link>https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-help</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-help</guid><category><![CDATA[orclapex]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Wed, 20 Aug 2025 19:27:53 GMT</pubDate><content:encoded><![CDATA[<p>In this fourth post of The Standard Component Attributes Anatomy Series, we’re diving deep into the Help standard attribute.</p>
<p>Although often overlooked, the Help attribute plays an important role in improving the user experience by providing clear, contextual guidance right where it’s needed.</p>
<p>Whether you're building internal tools or public-facing applications, leveraging this feature effectively can reduce user confusion and support requests.</p>
<h2 id="heading-help">Help</h2>
<p>As the name suggests, the <strong>Help</strong> sections in Oracle APEX provide a built-in mechanism for developers to define help text for various components. This information is processed and made available to end users in different ways, depending on the type of component.</p>
<p>Once again, the entered information is stored in the <strong>APEX metadata schema</strong>, which means that any changes to the help text will require a redeployment to propagate those changes to other environments.</p>
<p>For small applications, this feature is very convenient—it simplifies your life by keeping everything within the APEX builder. Help texts are automatically exported and included in your application deployment, so there's nothing extra to manage.</p>
<p>These help text strings are also <strong>available for translation</strong> in multi-language applications, making it easy to provide localized guidance for users in different regions.</p>
<p>However, in more complex or enterprise-level solutions, you might prefer to implement a <strong>custom help system</strong>—for example, storing help content in database tables—so that updates can be made dynamically without requiring a full redeployment.</p>
<h3 id="heading-page-level-help">Page-Level Help</h3>
<p>For <strong>page-level help</strong>, the content entered by the developer can be retrieved at runtime using the <code>HELP</code> procedure in the <code>APEX_APPLICATION</code> package. This gives you control over how and when to display help content to users.</p>
<p>For example, a modal dialog page—accessed via a button in the navigation bar—could include a Dynamic PL/SQL Region that displays the help text defined by the developer for the current page. This can be done using a call like the following:</p>
<pre><code class="lang-sql">APEX_APPLICATION.HELP(p_flow_id =&gt; :APP_ID);
</code></pre>
<p>More details can be found in the <a target="_blank" href="https://docs.oracle.com/en/database/oracle/apex/24.2/aeapi/HELP-Procedure.html">APEX API documentation.</a></p>
<h3 id="heading-setting-page-help">Setting Page Help</h3>
<p>Unfortunately, there is no official setter procedure exposed in the public APEX API to update page help text programmatically.</p>
<p>If you want to enable power users to edit page help dynamically, you may need to rely on undocumented procedures.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">⚠</div>
<div data-node-type="callout-text">Using undocumented APIs can be risky, as they may change without notice in future APEX releases. Use them cautiously and always test thoroughly.</div>
</div>

<h3 id="heading-item-level-help">Item-Level Help</h3>
<p>For <strong>items</strong>, APEX provides two distinct attributes:</p>
<ul>
<li><p><strong>Inline Help Text</strong></p>
</li>
<li><p><strong>Help Text</strong></p>
</li>
</ul>
<p>As the attribute descriptions suggest:</p>
<ul>
<li><p><strong>Inline Help Text</strong> is displayed directly next to or below the item. It provides <strong>immediate, field-level guidance</strong>, which is particularly useful for improving accessibility or offering quick hints.</p>
</li>
<li><p><strong>Help Text</strong> (the "old" style) is shown <strong>on demand</strong>—typically when the user clicks the help icon next to the item. This is ideal for <strong>more detailed or contextual explanations</strong> that don't need to be always visible.</p>
</li>
</ul>
<p>Because of this visual distinction, developers often use a <strong>short, concise message</strong> for inline help and reserve <strong>longer, richer content</strong> (potentially including HTML formatting and substitutions) for the help dialog.</p>
<p><strong>Note:</strong> Help text fields support HTML and dynamic substitutions, including application, page items, and system variables.</p>
<h3 id="heading-retrieving-help-text-from-the-data-dictionary">Retrieving Help Text from the Data Dictionary</h3>
<p>Like most metadata in APEX, help content is stored in the APEX dictionary views and can be queried. For example, to retrieve item-level help information, you can run:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> application_id,
       page_id,
       item_name,
       display_as,
       item_help_text,
       inline_help_text
<span class="hljs-keyword">FROM</span> apex_application_page_items
<span class="hljs-keyword">WHERE</span> application_id = :APP_ID;
</code></pre>
<p>The same applies to page-level help texts:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> application_id,
       page_id,
       help_text
<span class="hljs-keyword">FROM</span> apex_application_pages
<span class="hljs-keyword">WHERE</span> application_id = :APP_ID;
</code></pre>
<p>Enjoy life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX – The Standard Component Attributes Anatomy Series: Security]]></title><description><![CDATA[In this third post of The Standard Component Attributes Anatomy Series, I’m tackling the Security attribute. Since the Security section includes references to Authorization Schemes from Shared Components, we’ll briefly touch on that as well.
And beca...]]></description><link>https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-security</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-security</guid><category><![CDATA[orclapex]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Thu, 14 Aug 2025 13:31:35 GMT</pubDate><content:encoded><![CDATA[<p>In this third post of <strong>The Standard Component Attributes Anatomy Series</strong>, I’m tackling the <strong>Security</strong> attribute. Since the <em>Security</em> section includes references to Authorization Schemes from Shared Components, we’ll briefly touch on that as well.</p>
<p>And because there are specific <strong>security-related attributes</strong> at both the <em>page</em> and <em>item</em> levels, I’ll be covering those here too for a more complete picture.</p>
<h2 id="heading-security">Security</h2>
<p>In the <strong>Security</strong> section of a component's attributes, you may encounter different security-related options depending on the type of component you're working with. However, one attribute is common to all component types: the <strong>Authorization Scheme</strong>.</p>
<p>This attribute allows you to control access to a component by selecting a predefined authorization scheme—or its negation— meaning the component will be rendered or executed only if the user does meet the criteria defined in the scheme.</p>
<p>Unlike the Read-only attribute, which can be overridden by a child component, the Authorization Scheme and Server-Side Condition attributes are enforced at the parent level and cannot be bypassed or redefined by child components.</p>
<h3 id="heading-authorization-scheme"><strong>Authorization Scheme</strong></h3>
<p>Before assigning an authorization scheme to a component, you must first define it under <strong>Authorization Schemes</strong> in the <strong>Security</strong> section of <strong>Shared Components.</strong> Each scheme includes a logic block (typically PL/SQL or SQL) used to determine whether the current user meets the specified condition.</p>
<p>A key aspect to understand here is the <strong>Evaluation Point</strong>, which determines <strong>when</strong> and <strong>how often</strong> an authorization scheme is evaluated during a user session. As per Oracle's documentation:</p>
<ul>
<li><p><strong>Once per session</strong>: The scheme is evaluated only once per session, and the result is cached for all future uses.</p>
</li>
<li><p><strong>Once per page view</strong>: Evaluated once per request. If the same scheme is used in multiple components on the same page, the result is reused.</p>
</li>
<li><p><strong>Once per component</strong>: Evaluated individually for each component using the scheme, but results are cached in the session for reuse across requests.</p>
</li>
<li><p><strong>Always (No Caching)</strong>: The scheme is evaluated every time it is referenced—no caching occurs.</p>
</li>
</ul>
<p>Choosing the right evaluation point can have an impact on both <strong>performance</strong> and <strong>security</strong>, so it’s important to consider how dynamic your access rules are and how often they might change within a session.</p>
<p>You might be wondering—and rightly so—how <strong>authorization schemes</strong> differ from <strong>server-side conditions</strong>, since both are used to control component visibility or execution. While they may seem similar at first glance, authorization schemes serve a slightly different purpose and operate at a higher level.</p>
<p>Authorization schemes are typically <strong>centralized, reusable conditions</strong> that can be assigned to multiple components across your application. They support <strong>caching</strong>, which improves performance by avoiding repeated evaluations. This makes them ideal for access control scenarios, such as role-based restrictions, where the logic doesn't change frequently within a session.</p>
<p>On the other hand, <strong>server-side conditions</strong> are always evaluated <strong>at runtime</strong>, every time a component is processed. This behavior is functionally equivalent to setting an authorization scheme to <strong>"Always (No Caching)"</strong>, which disables caching altogether.</p>
<p>If you're interested in server-side conditions, check out the <a target="_blank" href="https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-server-side-condition">previous blog post</a> dedicated to that topic.</p>
<p>Keeping the number of <strong>authorization schemes</strong> at a reasonable level is key to maintaining long-term control and clarity in your Oracle APEX application. If you create too many narrowly scoped schemes—essentially micromanaging access—you risk creating a tangled web that’s hard to maintain. On the other hand, using only a few overly broad schemes might not give you the granularity needed for complex applications.</p>
<p>A good compromise is to design <strong>modular, reusable authorization schemes</strong>—but also build in a way to <strong>reset their cached results</strong> when necessary.</p>
<p>Let me explain with an example.</p>
<p>Imagine you’re building a <strong>project management application</strong>, where users can take on <strong>different roles in different projects</strong> (e.g., Manager in Project A, Viewer in Project B). To support this, you might have a <strong>select list</strong> that allows users to switch between projects, storing the selected project ID in an application item like <code>AI_PROJECT_ID</code>.</p>
<p>Now, suppose you have an <strong>authorization scheme</strong> that determines what a user is allowed to do based on their role in the selected project.</p>
<pre><code class="lang-sql">sample_security_package.auth_is_user_pm(
    p_username    =&gt; :APP_USER, 
    p_role_code   =&gt; 'PM', 
    p_project_id  =&gt; :AI_PROJECT_ID);
</code></pre>
<p>Since authorization schemes can cache results (depending on their evaluation point), you might run into a situation where the <strong>cached result doesn't reflect the newly selected project</strong>—because the scheme was already evaluated earlier in the session.</p>
<p>To solve this, you can <strong>manually reset the authorization cache</strong> when the user switches projects. This ensures that the next time the scheme is evaluated, it runs fresh with the correct context.</p>
<p>You can achieve this by calling the following <a target="_blank" href="https://docs.oracle.com/en/database/oracle/apex/24.2/aeapi/RESET_CACHE-Procedure.html">built-in</a> procedure:</p>
<pre><code class="lang-sql">APEX_AUTHORIZATION.RESET_CACHE;
</code></pre>
<h3 id="heading-page-specific-attributes">Page specific attributes</h3>
<p>Oracle APEX allows certain security settings, usually defined at the application level, to be overridden at the page level. This gives developers fine-grained control over how individual pages behave in terms of access, caching, and session protection.</p>
<p><strong>Authentication</strong></p>
<p>Determines whether a page requires authentication or is publicly accessible. One of the first things APEX does when generating a page is check whether the user is allowed to access it. This is handled by the Page Sentry function, which validates key security aspects such as the username, session validity, and more.</p>
<p>If the check passes, page generation continues; otherwise, the user is redirected to the URL defined in the "Go To" attribute of the authentication scheme in use.</p>
<p>While it's possible to define a custom Page Sentry function, it’s generally not recommended unless you have a very specific security need.</p>
<p><strong>Deep Linking</strong></p>
<p>Conceptually, deep linking allows users to "land" directly on a specific page within an application's flow, often with pre-set page items passed via URL parameters.</p>
<p>For example, in an email marketing campaign, your call-to-action might link to a specific APEX page. Each recipient could receive a dynamically generated URL that sets user preferences via parameters—ensuring the page displays personalized content that matches the email context.</p>
<p>In enterprise applications (where APEX is often used), you might want users to go directly to an <em>Approval Request</em> page, loading for instance <code>REQUEST_ID=1234</code> via the URL so they can immediately approve or reject it.</p>
<p>If this attribute is <strong>disabled</strong>, APEX will ignore and strip out any parameters passed in the page URL.</p>
<p>If <strong>enabled</strong>, and a valid APEX session exists, the page will load directly with all URL parameters preserved.<br />If the user isn’t authenticated, they’ll be redirected to the login screen first. After successful login, APEX will take them to the originally requested page, with all parameters intact.</p>
<p>This setting only applies to external requests. Internal navigation within the application is not affected by the Deep Linking setting.</p>
<p>By default, Deep Linking is disabled at the application level under the Security section in Shared Components. However, to simplify development, Deep Linking is always enabled when the user is logged into the APEX development environment.</p>
<p>It’s also important to note that if the target page’s security settings require a checksum for arguments, a valid checksum must be included along with the parameter values.</p>
<p>In scenarios like the email example, you’ll need to use the older API function <code>APEX_UTIL.PREPARE_URL</code> to generate the link URL, which allows you to explicitly define the type of checksum required. The newer <code>APEX_PAGE.GET_URL</code> function does <em>not</em> offer this level of control, making it unsuitable when protected items are involved.</p>
<p><strong>Page Access Protection</strong></p>
<p>Page access protection determines whether a request can render the page, whether it can set the values of page or application items, and under what conditions, such as requiring a checksum. The available options are:</p>
<ul>
<li><p><strong>Unrestricted</strong>: The page can be accessed via URL with or without session state arguments.</p>
</li>
<li><p><strong>Arguments Must Have Checksum</strong>: URL arguments require a checksum to ensure security.</p>
</li>
<li><p><strong>No Arguments Supported</strong>: The page can be accessed via URL but without any parameters.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755164001344/2892d8b2-15bc-453d-8a9b-85a6bd4e43c7.png" alt="Oracle APEX - Error message example shown when attemping to access a page passing arguments when no arguments are supported. " class="image--center mx-auto" /></p>
<ul>
<li><strong>No URL Access</strong>: The page can only be accessed internally (e.g., via branches), not by direct URL.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755164063608/a1b7346a-bf5b-4985-b0cf-27e1935e0cf1.png" alt="Oracle APEX - Error message example shown when trying to access a page by URL when no URL access is allowed" class="image--center mx-auto" /></p>
<p>Let’s focus for a moment on the second option, “Argument must have a checksum.” This default option instructs APEX to recalculate and validate the argument values against the provided checksum to ensure that users cannot manipulate the values. This attribute is related to the item security setting, “Session State Protection,” which dictates the type of checksum required for that specific item.</p>
<p>When generating a link to a specific page, APEX checks the target page and its item configuration to generate the correct checksum value. For example:</p>
<pre><code class="lang-xml">p3_empno=7566
clear=3
session=11155673235579
cs=1aGnPAKiqEoe1HtNuF.......OhLVhVG2cVLQwl4B84d
</code></pre>
<p>If you look closely at the arguments passed in the URL, you’ll notice that in this simple example, the page item <code>P3_EMPNO</code> is set to 7566 and the Clear Cache is set to 3. Behind the scenes, APEX adds a third argument, likely called <code>cv</code> (Checksum Value), which is a hash generated from the page and item values. When the page executes, APEX recalculates this hash to verify that the passed values haven’t been tampered with.</p>
<p><strong>Form Auto-Complete</strong></p>
<p>Enables or disables browser auto-complete on form fields. Setting this to <strong>Off</strong> adds <code>autocomplete="off"</code> to the HTML form tag. Behavior may vary across browsers.</p>
<p>As per <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/autocomplete">MDN</a>, the HTML autocomplete attribute lets web developers specify what if any permission the user agent has to provide automated assistance in filling out form field values, as well as guidance to the browser as to the type of information expected in the field.</p>
<p><strong>Browser Cache</strong><br />Controls whether the browser can cache page content:</p>
<ul>
<li><p><strong>Enabled</strong>: Allows caching in memory or on disk.</p>
</li>
<li><p><strong>Disabled</strong>: Sends the <code>cache-control: no-store</code> header to prevent caching—recommended for security.</p>
</li>
<li><p><strong>Application Default</strong>: Inherits the setting from the application-level security attributes.</p>
</li>
</ul>
<p>Oracle recommends disabling browser cache for pages displaying sensitive data, to avoid the risk of viewing stale content after logout via the browser's back button.</p>
<h3 id="heading-items-specific-attributes">Items specific attributes</h3>
<p>In the case of items, apart from the already mentioned generic <strong>Authorization scheme</strong>, we can set three additional attributes, two related to session state and one related to data sanitazion:</p>
<p><strong>Session State Protection</strong></p>
<p>Oracle APEX provides granular control over how page items handle session state and URL-based data submission through the <strong>Session State Protection</strong> attribute. This setting determines the security level for each item, helping prevent unauthorized data manipulation via URLs or forms.</p>
<ul>
<li><p>Unrestricted</p>
</li>
<li><p>Checksum Required – Application Level</p>
</li>
<li><p>Checksum Required – User Level</p>
</li>
<li><p>Checksum Required – Session Level</p>
</li>
<li><p>Restricted – May not be set from browser</p>
</li>
</ul>
<p>The first and last options are straightforward. Normally, items where the user is expected to enter data are set to <strong>Unrestricted</strong>. This must also be the case for hidden or display-only items that are dynamically populated after page rendering. For example, you might use the additional output of a Popup LOV to fill display-only fields. If a user selects a 'restaurant' record from a list, the corresponding full address could be automatically populated so it can be submitted and processed later.</p>
<p>Restricted, on the other hand, is suitable for items that are computed or fetched during page rendering and are not intended to be modified by the user. In my experience, this setting is rarely applied at the page level but is commonly used for application items that are precomputed at the start of a session and control application behavior.</p>
<p>The other three options relate to checksums. They instruct APEX to validate that the argument passed corresponds to the checksum value, ensuring data integrity when fetching and rendering the page. These options allow you to control the security level of the checksum:</p>
<ul>
<li><p><strong>Session Level (default, most secure):</strong> The checksum applies only to the current session. This is ideal for forms triggered from a record in a report within a valid user session.</p>
</li>
<li><p><strong>User Level:</strong> The checksum is valid as long as the application user is the same. This is useful when a user wants to save a bookmark to a specific page with arguments to access later.</p>
</li>
<li><p><strong>Application Level (least secure):</strong> The checksum is valid for any user of the application. This is typically used for email links, where multiple users might access the page with the same arguments. In this case, it’s advisable to add an extra security check to ensure that the user has the proper rights to view the record.</p>
</li>
</ul>
<p><strong>Store value encrypted in session state</strong></p>
<p>This attribute is straightforward—it lets you encrypt the item’s value when stored in session state. If the item contains sensitive data, enabling encryption ensures that the value is protected in APEX’s session state management tables.</p>
<p>Without encryption, anyone with access to the APEX metadata tables could potentially query and retrieve this sensitive information.</p>
<p>As mentioned, APEX is secure by default, so this feature is enabled automatically.</p>
<p><strong>Restricted characters</strong></p>
<p>This attribute allows you to declaratively sanitize values submitted by the user. As a developer, you may recall the first security rule: “never trust the user.” Out of the box, APEX supports a limited set of parameters for the escape function, which include:</p>
<ul>
<li><p>All characters can be saved</p>
</li>
<li><p>Allowlist for a–z, 0–9, and space</p>
</li>
<li><p>Blocklist HTML command characters (&lt; &gt; ")</p>
</li>
<li><p>Blocklist &amp; &lt; &gt; " / ; , * | = % and --</p>
</li>
<li><p>Blocklist &amp; &lt; &gt; " / ; , * | = % or -- and new line</p>
</li>
</ul>
<p>For example, if you configure it to allow only letters and numbers, APEX will raise an error whenever the submitted value contains any other characters.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1755159205497/6d3a61f6-58b1-47b0-876f-33ca56f4040c.png" alt="Oracle APEX - Example error when a restricted character is submitted" class="image--center mx-auto" /></p>
<p>If these options don’t meet your needs, APEX—as always—gives you full control over your settings. In this case, the APEX_ESCAPE package allows you to sanitize and escape user inputs with greater granularity. You can find the full documentation <a target="_blank" href="https://docs.oracle.com/en/database/oracle/apex/24.2/aeapi/APEX_ESCAPE.html">here</a>.</p>
<p>Enjoy life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX – The Standard Component Attributes Anatomy Series: Read Only]]></title><description><![CDATA[As part of my ongoing preparation for an upcoming presentation on APEX items, I’m continuing the blog series that explores the fundamental, often underused capabilities of Oracle APEX.
In the first post, we looked at the Server-side Condition attribu...]]></description><link>https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-read-only</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-read-only</guid><category><![CDATA[Oracle]]></category><category><![CDATA[orclapex]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Mon, 04 Aug 2025 19:07:51 GMT</pubDate><content:encoded><![CDATA[<p>As part of my ongoing preparation for an upcoming presentation on APEX items, I’m continuing the blog series that explores the fundamental, often underused capabilities of Oracle APEX.</p>
<p>In the first post, we looked at the <a target="_blank" href="https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-server-side-condition"><em>Server-side Condition</em> attribute</a> and how it influences component behavior at runtime. Now, in this second post, we shift focus to another key attribute: Read-Only.</p>
<p>While it may seem straightforward, <em>Read-Only</em> in APEX is packed with flexibility and nuance. From static settings to conditional logic using PL/SQL or SQL expressions, understanding how this attribute works under the hood can help you build cleaner, more secure, and more maintainable applications.</p>
<h2 id="heading-read-only">Read Only</h2>
<p>Very much like server-side conditions, the <strong>Read Only</strong> attribute in APEX also supports its own conditional logic. This allows you to control when a component—typically an item or region—should be rendered in a non-editable state, based on dynamic conditions.</p>
<p>Just like with server-side conditions, you can base this on item values, SQL queries, or PL/SQL expressions, giving you fine-grained control over when users can or cannot modify data.</p>
<p>Keep in mind that read-only conditions cascade: if a region is set to read-only, all items within it will also be read-only by default. The following example shows the default look and feel of read-only floating label templates in Universal Theme 24.2, with the read-only condition applied at the form level.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753128074557/93e9e32d-e265-4ae1-a01a-d82721aadb95.png" alt="Oracle APEX - Read only sample form" class="image--center mx-auto" /></p>
<p>If you want a specific item—say a search field—to always remain editable regardless of the region’s read-only state, simply set that item’s <strong>Read Only Condition</strong> to <strong>“Never.”</strong> This effectively overrides the region setting and ensures the item stays editable.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753128398853/b0d6f2e8-4827-43d8-b15c-500c0ef2bc0a.png" alt="Oracle APEX - Read Only form example with editable item" class="image--center mx-auto" /></p>
<p>Perhaps more interesting—and more important—is understanding what happens behind the scenes when the <code>read-only</code> attribute is set to <code>true</code>. Let’s break down the generated code to see exactly what’s happening at the item level.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"t-Form-itemWrapper"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
        <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span>
        <span class="hljs-attr">data-for</span>=<span class="hljs-string">"P3_JOB"</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">"Wdy9uFm1u3IG9An.....fRZrMefjsTTQevJoFWH7pjGkqpAX7K_OtOufMZHg"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"P3_JOB"</span> 
        <span class="hljs-attr">name</span>=<span class="hljs-string">"P3_JOB"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"js-accessible-readonly apex-item-text-readonly"</span> 
        <span class="hljs-attr">aria-readonly</span>=<span class="hljs-string">"true"</span>
        <span class="hljs-attr">spellcheck</span>=<span class="hljs-string">"false"</span> 
        <span class="hljs-attr">inputmode</span>=<span class="hljs-string">"none"</span> 
        <span class="hljs-attr">autocomplete</span>=<span class="hljs-string">"off"</span> 
        <span class="hljs-attr">value</span>=<span class="hljs-string">"CLERK"</span> 
        <span class="hljs-attr">size</span>=<span class="hljs-string">"32"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<h3 id="heading-read-only-attribute-in-apex">Read-Only Attribute in APEX</h3>
<p>A typical developer might expect Oracle APEX to use the standard HTML <code>readonly</code> attribute to make an item read-only. However, that’s not how APEX works.</p>
<p>Instead, Oracle APEX simulates read-only behavior using <strong>CSS and JavaScript</strong>, rather than relying on the native <code>readonly</code> attribute. Why? While we can’t say for certain, it seems APEX opts for a <em>“fake read-only”</em> approach for a few practical reasons:</p>
<ul>
<li><p>The input remains <strong>focusable</strong>, which benefits screen readers and allows users to <strong>copy</strong> values.</p>
</li>
<li><p>Users <strong>can’t type</strong> into the field—it looks and acts read-only.</p>
</li>
<li><p>The field's <strong>value is submitted</strong> with the form, unlike <code>disabled</code> inputs, which are ignored during submission.</p>
</li>
</ul>
<p>This hybrid method gives APEX fine-grained control over the user experience while maintaining accessibility and functionality.</p>
<p><strong><em>UPDATE:</em></strong> <em>After publishing this post, the Oracle APEX team reached out to share the main reason behind this behavior. It turns out that APEX’s “fake read-only” approach isn’t just a design choice—it’s a workaround for a</em> <a target="_blank" href="https://issues.chromium.org/issues/40801366"><em>Chromium bug</em></a> <a target="_blank" href="https://issues.chromium.org/issues/40801366"><em>that causes</em></a> <em>accessibility issues for keyboard and screen reader users when using the native</em> <code>readonly</code> <em>attribute on text and textarea elements.</em></p>
<p><em>By simulating read-only with CSS and JavaScript, APEX avoids these problems while still ensuring values are submitted with the form. According to the team, if the Chromium bug is ever fixed, APEX will revert to using the native</em> <code>readonly</code> <em>attribute.</em></p>
<h3 id="heading-css-classes-used-for-read-only-items">CSS Classes Used for Read-Only Items</h3>
<p>Oracle APEX uses a combination of CSS classes to simulate read-only behavior, rather than relying on the native HTML <code>readonly</code> attribute. Two key classes are involved:</p>
<p><code>js-accessible-readonly</code><br />This class informs APEX’s JavaScript that the input should behave as read-only. Although users can’t modify the field, its value is still submitted with the form. It serves as a functional indicator rather than a visual one.</p>
<p><code>apex-item-text-readonly</code><br />This styling class handles the visual aspect. It makes the input look like a regular text field, but with a grayed-out or non-editable appearance to clearly signal that it’s read-only.</p>
<p>Together, these classes provide consistent behavior and appearance across different components, while maintaining accessibility and proper form submission.</p>
<p>If you're curious about the specific CSS properties applied to read-only items, you can explore them directly. Just open your browser’s developer tools or inspect the <code>core.css</code> file in your APEX installation's static files. Look for any of the following read-only-related classes (e.g., <code>apex-item-autocomplete-readonly</code>, <code>apex-item-text-readonly</code>, etc.) to see how APEX handles different item types in read-only mode.</p>
<h3 id="heading-aria-attribute">ARIA Attribute</h3>
<p>The <code>aria-readonly</code> attribute is used for <strong>accessibility</strong>. It tells screen readers and assistive technologies that an input is read-only—even if the standard HTML <code>readonly</code> attribute is not present. This helps maintain a consistent experience for all users.</p>
<h3 id="heading-inputmode-attribute">Inputmode Attribute</h3>
<p>As per the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/inputmode">MDN Web Docs</a>, the <code>inputmode</code> global attribute is an <strong>enumerated attribute</strong> that provides a hint about the type of data a user is expected to enter. This helps browsers display a context-appropriate <strong>virtual keyboard</strong>, particularly on mobile devices.</p>
<p>In the context of read-only fields, <code>inputmode</code> is sometimes set to <code>none</code> to discourage input.</p>
<h3 id="heading-checksum">Checksum</h3>
<p>Perhaps the most important aspect of APEX's read-only mechanism is the <strong>hidden item</strong> generated alongside the read-only input. This hidden field stores a <strong>checksum value</strong>, which is submitted together with the original item.</p>
<p>During page processing, APEX uses this checksum to automatically validate that the value of the read-only item hasn't been tampered with by the user. If the checksum doesn't match, APEX raises a security error—ensuring data integrity for read-only items.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753131950054/a2ce5ffe-308b-4cea-b6ac-96251ec3a11a.png" alt="Oracle APEX - Checksum validation error example" class="image--center mx-auto" /></p>
<h3 id="heading-when-inputs-go-read-only">When Inputs Go Read-Only</h3>
<p>Apart from the changes at the item attribute level, APEX also generates 'special' form items—such as date pickers, select lists, and popup LOVs—as input elements with their corresponding display values.</p>
<p>These components behave slightly differently when marked as read-only, often being rendered as plain text while still maintaining their functional styling. In all cases, APEX generates the necessary checksums behind the scenes to ensure data integrity and prevent tampering, just as it would for standard items.</p>
<h3 id="heading-processing-read-only-items">Processing Read-Only Items</h3>
<p>Last but not least, it’s worth mentioning the processing behavior of read-only forms or pages. When a page or region is marked as read-only, the backend processing remains unchanged. Validations will still run against read-only items just as they would for editable ones, and page processes—including custom PL/SQL processes—will continue to execute as expected.</p>
<p>You might assume that the <strong>Automatic Row Processing (DML)</strong> process would be skipped if the entire form region is rendered as read-only—but that’s not the case. APEX does not automatically disable processes based on the read-only state of a region or item. It’s up to the developer to implement any conditional logic to skip processing if needed.</p>
<p>That concludes everything I wanted to share about the read-only attribute in Oracle APEX.</p>
<p>Enjoy life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX – The Standard Component Attributes Anatomy Series: Server-side Condition]]></title><description><![CDATA[Preparing for a presentation on APEX items, I’m starting a new series of blog posts exploring the basic capabilities of APEX. The goal is to gain a deeper understanding of how things work behind the scenes and how we can make the most of them.
This f...]]></description><link>https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-server-side-condition</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-the-standard-component-attributes-anatomy-series-server-side-condition</guid><category><![CDATA[orclapex]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Mon, 28 Jul 2025 20:42:56 GMT</pubDate><content:encoded><![CDATA[<p>Preparing for a presentation on APEX items, I’m starting a new series of blog posts exploring the basic capabilities of APEX. The goal is to gain a deeper understanding of how things work behind the scenes and how we can make the most of them.</p>
<p>This first post in the series focuses on standard attributes shared across APEX components. While these attributes aren’t limited to items, understanding them is essential to fully leverage what APEX has to offer. In this post, we take a deep dive into the Server-side Condition attribute.</p>
<h2 id="heading-server-side-conditions">Server-Side Conditions</h2>
<p>As the name suggested, <strong>Server-Side</strong> <strong>Condition</strong> attribute controls <strong>whether a component is rendered or processed</strong>, depending on the context. It applies to almost anything in APEX — regions, items, buttons, dynamic actions, validations, processes — and even to shared components like navigation menu entries or breadcrumbs.</p>
<p>When we say a condition controls rendering, it means that based on the condition you define, <strong>APEX decides whether to generate the corresponding HTML or JavaScript code for that component.</strong><br />If the condition is not met, the code simply won’t exist in the HTTP response sent to the client — it’s as if the component doesn’t exist on that page load.</p>
<p>When it comes to processes, validations, or computations, the condition determines whether that PL/SQL block is executed on the server.</p>
<h3 id="heading-types">Types</h3>
<p>Oracle APEX offers a wide variety of predefined condition types, which can be broadly grouped into:</p>
<ul>
<li><p><strong>SQL-based checks</strong> (like “Rows returned”)</p>
</li>
<li><p><strong>PL/SQL or SQL Expressions or function bodies</strong></p>
</li>
<li><p><strong>Request &amp; item value comparisons</strong></p>
</li>
<li><p><strong>User or session context checks</strong> (like language, authentication, )</p>
</li>
<li><p><strong>Never</strong></p>
</li>
</ul>
<blockquote>
<p><strong>Tip:</strong> Different components offer different types of conditions, and each condition type may require specific attributes. Be curious—explore the help texts and list of values to discover all the options available.</p>
</blockquote>
<p>These conditions are essentially declarative (low-code) constructs that you can easily configure. Behind the scenes, however, every one of these conditions ultimately translates into a piece of PL/SQL code.</p>
<p>For example, when you use the <strong>Request = Value</strong> type, you simply specify the value to compare against.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752599278234/f7223f99-9f95-42d6-bbed-69056acc9a75.png" alt class="image--center mx-auto" /></p>
<p>Most likely, the APEX engine will then translate this into something like the following PL/SQL check behind the scenes:</p>
<pre><code class="lang-sql">:REQUEST = 'LOW_CODE'
</code></pre>
<p>As a personal preference—and given that PL/SQL is the engine behind the scenes in Oracle APEX—I prioritize PL/SQL expressions over SQL for conditions. When you write a condition using SQL, APEX translates it into dynamic SQL, which introduces a context switch that can impact performance over time. My general recommendation: avoid using SQL in conditions whenever possible. Stick with PL/SQL and you’ll be on the safe side 😄</p>
<p>A common example I’ve encountered in practice:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753734610548/420324d9-27fd-4ed1-b96a-9f7b1bd157d9.png" alt="Oralce APEX - Application Builders server-side condition bad practice example" class="image--center mx-auto" /></p>
<p>Instead, I prefer to use a PL/SQL Expression with the following code:</p>
<pre><code class="lang-sql">to_date(:P1_FROM_DATE, :APP_NLS_DATE_FORMAT ) &lt; sysdate
</code></pre>
<h3 id="heading-server-side-conditions-in-the-apex-dictionary-views">Server-Side Conditions in the APEX Dictionary Views</h3>
<p>To fully leverage the potential of the <strong>Server-side Condition</strong> attribute, you can rely on APEX data dictionary views to dynamically build conditions based on your application’s metadata. For example, if you want to implement an alert region on <strong>Page 0</strong>, you could do something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752600492401/1b03032d-379d-4507-9f39-8e0fa56e335f.png" alt="Oracle APEX - Alert sample region in page 0" class="image--center mx-auto" /></p>
<p>You might not want that region to render in modal dialogs. In that case, you can easily target only normal pages by using a <strong>Rows Returned</strong> condition like this:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> <span class="hljs-number">1</span>
<span class="hljs-keyword">from</span> apex_application_pages
 <span class="hljs-keyword">where</span> application_id = :app_id
 <span class="hljs-keyword">and</span> page_id = :app_page_id
 <span class="hljs-keyword">and</span> page_mode = <span class="hljs-string">'Normal'</span>;
</code></pre>
<p>Oracle APEX Dictionary Views can also help you identify the server-side conditions used throughout your applications.</p>
<p>By querying these views, you can see where and how different conditions are applied, which often reveals opportunities for code improvements or better reuse. For example, you can select condition-related columns from multiple views like this to gain valuable insights:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> 
    application_id, 
    page_id, 
    region_name, 
    condition_type,
    condition_type_code,
    condition_expression1,
    condition_expression2
  <span class="hljs-keyword">from</span> apex_application_page_regions
 <span class="hljs-keyword">where</span> application_id = :app_id
</code></pre>
<p>This would result in something like the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752601841638/2daea447-ec6f-4824-b580-4737de73a4eb.png" alt="Oracle APEX - Data dictionary query result for condition columns" class="image--center mx-auto" /></p>
<h3 id="heading-never-say-never">Never say never</h3>
<p>it’s worth mentioning that the once-popular <strong>“Never”</strong> condition has largely been replaced by a more flexible and easier-to-use option: setting the <strong>Build Option</strong> to <strong>“Commented Out”</strong> (found under the component’s configuration attributes).</p>
<p>This approach is especially handy during debugging, as it lets you temporarily disable the rendering of a component to help isolate problems. However, be aware of a drawback: when you change a condition to <strong>Never</strong>, any existing condition gets removed, and there’s a good chance you might forget what it was before—so take note of it somewhere first!</p>
<blockquote>
<p><strong>Tip:</strong> Unlike server-side conditions, which are evaluated independently for each component and not cached, authorization schemes support configurable caching strategies such as <em>Once per session</em> or <em>Once per page view</em>. This makes them more efficient when applying the same logic across multiple components—plus easier to maintain.</p>
</blockquote>
<p>Enjoy life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX – Taking Advantage of Helper Classes]]></title><description><![CDATA[Glad to see that the helper classes I missed in previous APEX versions—and had been discussing theoretically with the APEX Universal Theme team—have now been natively integrated into the latest version, 24.2.
Sounds like a great opportunity to share ...]]></description><link>https://blog.lucashir.eu/oracle-apex-taking-advantage-of-helper-classes</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-taking-advantage-of-helper-classes</guid><category><![CDATA[orclapex]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Tue, 25 Feb 2025 22:22:51 GMT</pubDate><content:encoded><![CDATA[<p>Glad to see that the helper classes I missed in previous APEX versions—and had been discussing theoretically with the APEX Universal Theme team—have now been natively integrated into the latest version, 24.2.</p>
<p>Sounds like a great opportunity to share a quick post to help others who faced the same issue—or perhaps didn’t even realize there was one!</p>
<p>In this example, we'll use some of the bundled helpers from the Oracle APEX Universal Theme to solve common UI challenges.</p>
<h2 id="heading-the-problem">The Problem</h2>
<p>They say a picture is worth a thousand words, so here’s a great example of a common problem I face—and maybe one you’ll notice from now on too.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740517544253/8682398c-62f4-483f-bf76-b6f7d464c20c.png" alt="Oracle APEX - Simple Dashboard page example with user interface inconsistencies" class="image--center mx-auto" /></p>
<h2 id="heading-1-automatic-column-span">1# Automatic Column Span</h2>
<p>My issue in this case is related to the automatic region span. By default, APEX evenly distributes regions within the same row unless specified otherwise. If you want to change this—especially if you're new to the low-code world—you should know that you can control both the column span and starting position <strong>declaratively</strong> from the region Layout attributes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740517670514/4f83ccde-4023-4388-8191-e4ec826433b9.png" alt="Oracle APEX - Page builders column span attribute for region" class="image--center mx-auto" /></p>
<p>As you might know, the Universal Theme implements a 12-column grid system. You can learn more about it <a target="_blank" href="https://apex.oracle.com/pls/apex/r/apex_pm/ut/grid-layout">here</a>. In my case, it would be enough to set the Instruction regions to use 4 out of the 12 columns, allowing the Charts to automatically span across the remaining 8 columns.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740518090915/72aaafe4-e7d6-40d3-8f91-2ab9a6193671.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Remember that holding <strong>CTRL</strong> while selecting a component, either from the component tree or the layout panel, allows you to select multiple components at once.</div>
</div>

<p>The result might already look a bit more attractive on a desktop:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740518248241/db8ecc5d-c2bf-453c-ac75-3b0f6cd71e19.png" alt="Oracle APEX - Dashboard with two rows. Each row with a bigger chart region and a smaller instructions region on the side. " class="image--center mx-auto" /></p>
<p>But unfortunately, that wouldn’t be the case for a mobile or even a tablet display:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740518439308/7222facf-3605-4921-b14a-29b0c8da56d8.png" alt class="image--center mx-auto" /></p>
<p>To solve this issue, there isn't a "no-code" solution, but a low-code approach is available instead.</p>
<p>By manually setting the breakpoints for our regions using native CSS classes, we can control when the region spans change. In this case, adding the following CSS classes to the <strong>Column CSS</strong> attribute for the Chart and Instruction regions will improve the situation:</p>
<p><code>col-xxs-12 col-xs-12 col-sm-6</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740519147349/c00aba25-a5db-4af2-b4aa-c0e7979e0eb8.png" alt class="image--center mx-auto" /></p>
<p>The <code>col-AAA-NN</code> classes define how many columns a specific element will span on different screen sizes. When setting multiple elements on the same row, make sure that the total column span for each screen size always adds up to 12.</p>
<p>For example, if you have two regions and one is set to <code>col-xxs-12 col-xs-6 col-sm-4 col-md-3 col-lg-2</code>, the second region will need to have classes that complete the 12 columns. In this case, it should be set to: <code>col-xxs-12 col-xs-6 col-sm-8 col-md-9 col-lg-10</code>.</p>
<h2 id="heading-2-growing-containers">2# Growing containers</h2>
<p>You might notice in our example that the instruction boxes next to the charts don’t match the charts' size. While they might align on certain screen sizes, APEX doesn’t guarantee this by default. Fortunately, there’s a simple way to fix it using flex helper classes, which I have already explained <a target="_blank" href="https://blog.lucashir.eu/oracle-apex-native-equal-height-regions-in-the-universal-theme">here</a>.</p>
<p>The result after applying the <code>u-flex-grow-1</code> class:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740519993591/9bb8d530-c9d7-443a-a0cb-1a1d8eb1d8d0.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-3-fonts">#3 Fonts</h2>
<p>A real added value, at least for me, are the new typography classes. You can read more about them in the official Universal Theme documentation <a target="_blank" href="https://apex.oracle.com/pls/apex/r/apex_pm/ut/content-modifiers">here</a><a target="_blank" href="https://apex.oracle.com/pls/apex/r/apex_pm/ut/content-modifiers">.</a></p>
<p>As a quick demo, I just added these classes: <code>u-text-body-md u-text-lighter u-hyphen</code> in the <strong>CSS</strong> attribute of the region, alongside the already existing <code>u-flex-grow-1</code> (see the previous topic).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740520522444/68a011f9-04b4-40c5-92de-2cb316e3764e.png" alt class="image--center mx-auto" /></p>
<p>The result would look something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740520581509/dee41fa0-c541-4f44-ad63-08d8fb93f905.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-4-collapse-order">#4 Collapse Order</h2>
<p>Last but not least, there's the problem that bothers me the most. In the case of an alternate layout, where there is an intercalation of text and images or charts and text, like in this example, the collapse order becomes crucial. Typically, on a mobile device, there will be two images (or charts) displayed next to each other, which makes the order of their collapse important.</p>
<p>Take this example and notice that the two instruction regions are now stacked, one on top of the other:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740521027935/3a3aeca2-276a-44cc-b3c9-a78173e329db.png" alt class="image--center mx-auto" /></p>
<p>Ugly enough, right? Luckily, in APEX 24.2, a native solution for this has been included that allows us to set the collapse order of the regions using the same principle we use for the column span.</p>
<p>By adding <code>u-order-xxs-2 u-order-xs-2</code> to the already existing <code>u-flex col-xxs-12 col-xs-12 col-sm-6</code>, we can achieve the final version of our dashboard:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1740521464610/31bed5a6-4310-447d-a844-d385d05e9bb0.png" alt class="image--center mx-auto" /></p>
<p>Enjoy Life!</p>
]]></content:encoded></item><item><title><![CDATA[SQL - Calculating Date Offset While Excluding Weekends]]></title><description><![CDATA[In a current project, I needed to calculate the date offset while excluding weekends. Initially, this was solved using a loop in PL/SQL, which I consider a less efficient approach.
To optimize it, I created a straightforward SQL query that handles th...]]></description><link>https://blog.lucashir.eu/sql-calculating-date-offset-while-excluding-weekends</link><guid isPermaLink="true">https://blog.lucashir.eu/sql-calculating-date-offset-while-excluding-weekends</guid><category><![CDATA[oracle-sql]]></category><category><![CDATA[SQL]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Tue, 15 Oct 2024 10:21:21 GMT</pubDate><content:encoded><![CDATA[<p>In a current project, I needed to calculate the date offset while excluding weekends. Initially, this was solved using a loop in PL/SQL, which I consider a less efficient approach.</p>
<p>To optimize it, I created a straightforward SQL query that handles this logic directly, ensuring only business days are considered.</p>
<p>I also enhanced the query to include the ability to move both backward and forward in time, all controlled by a single bind variable that defines the offset.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span>
    d
<span class="hljs-keyword">FROM</span>
    (
        <span class="hljs-keyword">SELECT</span>
            d,
            <span class="hljs-keyword">ROWNUM</span> rn
        <span class="hljs-keyword">FROM</span>
            (
                <span class="hljs-keyword">SELECT</span>
                    <span class="hljs-keyword">sysdate</span> + ( ( <span class="hljs-keyword">level</span> ) * <span class="hljs-keyword">abs</span>(:p_offset) / :p_offset )         d,
                    to_char(<span class="hljs-keyword">sysdate</span> +(<span class="hljs-keyword">level</span>), <span class="hljs-string">'DY'</span>, <span class="hljs-string">'NLS_DATE_LANGUAGE=ENGLISH'</span>) <span class="hljs-keyword">AS</span> target_day
                <span class="hljs-keyword">FROM</span>
                    dual
                <span class="hljs-keyword">CONNECT</span> <span class="hljs-keyword">BY</span>
                    <span class="hljs-keyword">level</span> &lt;= <span class="hljs-keyword">abs</span>(:p_offset) * <span class="hljs-number">2</span>
            )
        <span class="hljs-keyword">WHERE</span>
            target_day <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">IN</span> ( <span class="hljs-string">'SAT'</span>, <span class="hljs-string">'SUN'</span> )
    )
<span class="hljs-keyword">WHERE</span>
    rn = <span class="hljs-keyword">abs</span>(:p_offset);
</code></pre>
<p>In case you want to implement holidays as well, you can rely on a REST API for that:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">WITH</span> dy <span class="hljs-keyword">AS</span> (
    <span class="hljs-keyword">SELECT</span>
        <span class="hljs-keyword">sysdate</span> + ( ( <span class="hljs-keyword">level</span> ) * <span class="hljs-keyword">abs</span>(:p_offset) / :p_offset )         d,
        to_char(<span class="hljs-keyword">sysdate</span> +(<span class="hljs-keyword">level</span>), <span class="hljs-string">'DY'</span>, <span class="hljs-string">'NLS_DATE_LANGUAGE=ENGLISH'</span>) <span class="hljs-keyword">AS</span> target_day
    <span class="hljs-keyword">FROM</span>
        dual
    <span class="hljs-keyword">CONNECT</span> <span class="hljs-keyword">BY</span>
        <span class="hljs-keyword">level</span> &lt;= <span class="hljs-keyword">abs</span>(:p_offset) * <span class="hljs-number">2</span>
), dd <span class="hljs-keyword">AS</span> (
    <span class="hljs-keyword">SELECT</span>
        <span class="hljs-keyword">MIN</span>(d) mind,
        <span class="hljs-keyword">MAX</span>(d) maxd
    <span class="hljs-keyword">FROM</span>
        dy
), h <span class="hljs-keyword">AS</span> (
    <span class="hljs-keyword">SELECT</span>
        <span class="hljs-keyword">TO_DATE</span>(holiday_date, <span class="hljs-string">'yyyy-mm-dd'</span>) holiday_date,
        holiday_type
    <span class="hljs-keyword">FROM</span>
        JSON_TABLE ( apex_web_service.make_rest_request(p_url =&gt; <span class="hljs-string">'https://date.nager.at/api/v3/PublicHolidays/2024/US'</span>, p_http_method =&gt; <span class="hljs-string">'GET'</span>
        ), <span class="hljs-string">'$[*]'</span>
            <span class="hljs-keyword">COLUMNS</span> (
                holiday_date <span class="hljs-built_in">VARCHAR2</span> ( <span class="hljs-number">20</span> ) <span class="hljs-keyword">PATH</span> <span class="hljs-string">'$.date'</span>,
                holiday_type <span class="hljs-built_in">VARCHAR2</span> ( <span class="hljs-number">50</span> ) <span class="hljs-keyword">PATH</span> <span class="hljs-string">'$.types[0]'</span>
            )
        )
    <span class="hljs-keyword">WHERE</span>
        holiday_type = <span class="hljs-string">'Public'</span>
), hh <span class="hljs-keyword">AS</span> (
    <span class="hljs-keyword">SELECT</span>
        holiday_date
    <span class="hljs-keyword">FROM</span>
             h
        <span class="hljs-keyword">CROSS</span> <span class="hljs-keyword">JOIN</span> dd
    <span class="hljs-keyword">WHERE</span>
        holiday_date <span class="hljs-keyword">BETWEEN</span> mind <span class="hljs-keyword">AND</span> maxd
)
<span class="hljs-keyword">SELECT</span>
    *
<span class="hljs-keyword">FROM</span>
    (
        <span class="hljs-keyword">SELECT</span>
            d,
            <span class="hljs-keyword">ROWNUM</span> rn
        <span class="hljs-keyword">FROM</span>
            (
                <span class="hljs-keyword">SELECT</span>
                    trunc(d) d
                <span class="hljs-keyword">FROM</span>
                    dy
                <span class="hljs-keyword">WHERE</span>
                    target_day <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">IN</span> ( <span class="hljs-string">'SAT'</span>, <span class="hljs-string">'SUN'</span> )
                <span class="hljs-keyword">MINUS</span>
                <span class="hljs-keyword">SELECT</span>
                    holiday_date d
                <span class="hljs-keyword">FROM</span>
                    hh
            )
    )
<span class="hljs-keyword">WHERE</span>
    rn = <span class="hljs-keyword">abs</span>(:p_offset);
</code></pre>
<p>Enjoy Life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX - Native Maps with Draggable Markers]]></title><description><![CDATA[As you might know, the map region feature was introduced in APEX 21.1 and further enhanced in 23.2, when custom map backgrounds were added to the supported feature list.
While the MapLibre APEX implementation offers a robust set of declarative featur...]]></description><link>https://blog.lucashir.eu/oracle-apex-native-maps-with-draggable-markers</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-native-maps-with-draggable-markers</guid><category><![CDATA[orclapex]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Fri, 04 Oct 2024 06:33:33 GMT</pubDate><content:encoded><![CDATA[<p>As you might know, the map region feature was introduced in APEX 21.1 and further enhanced in 23.2, when custom map backgrounds were added to the supported feature list.</p>
<p>While the MapLibre APEX implementation offers a robust set of declarative features, there were still some missing functionalities that were crucial for my latest project.</p>
<p>As usual, when a client has a problem, there are two ways to approach it: either I have the solution, or I find one.</p>
<p>In this case, it was the latter.</p>
<h2 id="heading-the-problem">The problem</h2>
<p>In this particular case, the goal was to display multiple markers, representing spatial points, on a map. The key functionality required was to allow users to interact with the map by manually adjusting the position of each marker. This would provide a way for users to fine-tune the location of these spatial points directly on the map interface.</p>
<p>As the markers are moved, the updated coordinates would need to be captured and reflected in real time, with the new positions being automatically saved and updated in a corresponding database table for each record. This feature was essential to ensure data accuracy and flexibility for the user.</p>
<h2 id="heading-considering-a-solution">Considering a solution</h2>
<p>It’s no secret that I’m a fan of solving problems in Oracle APEX in the simplest and most native way possible. While exploring my options for this particular challenge, I quickly realized a few limitations:</p>
<ul>
<li><p>There was no declarative option to create draggable markers within the Maps Region.</p>
</li>
<li><p>There were no dynamic actions available that could handle or simulate this behavior.</p>
</li>
<li><p>The component lacked an 'Initialization JavaScript Function' that would suggest room for further customization or flexibility.</p>
</li>
<li><p>To make matters more challenging, there was little to no information available online about how to address a similar issue.</p>
</li>
</ul>
<p>This left me with no choice but to dive deeper and come up with a custom solution.</p>
<h2 id="heading-exploring-maplibre-documentation">Exploring MapLibre documentation</h2>
<p>The first thing I needed to do was understand the technology behind the scenes and determine whether the JavaScript library supported this functionality at all.</p>
<p>After diving into the MapLibre documentation, I quickly discovered that draggable markers were indeed a built-in feature. It was as simple as setting the <code>draggable</code> flag to <code>true</code> when creating the markers.</p>
<pre><code class="lang-javascript">    <span class="hljs-keyword">new</span> maplibregl.Marker({ <span class="hljs-attr">draggable</span>: <span class="hljs-literal">true</span>});
</code></pre>
<p>You can find two working examples in the official documentation:</p>
<ul>
<li><p><a target="_blank" href="https://maplibre.org/maplibre-gl-js/docs/examples/drag-a-point/">Create a draggable point</a></p>
</li>
<li><p><a target="_blank" href="https://maplibre.org/maplibre-gl-js/docs/examples/drag-a-marker/">Create a draggable Marker</a></p>
</li>
</ul>
<h2 id="heading-exploring-the-oracle-apex-javascript-api">Exploring the Oracle APEX JavaScript API</h2>
<p>The next logical step was to check the Oracle APEX JavaScript API documentation to find a way to influence how APEX creates the points on the map.</p>
<p>As you might have already noticed, there is a <code>mapRegion</code> interface in the API, which, as stated in the documentation, is used to access the properties and methods of the spatialMap API. More information can be found <a target="_blank" href="https://docs.oracle.com/en/database/oracle/apex/24.1/aexjs/mapRegion.html">here</a>.</p>
<p>Unfortunately, there is no method or property in the API that would allow me to solve my problem in an obvious way. However, after some time spent reading, I eventually found what I needed.</p>
<h3 id="heading-the-getmapobject-method"><strong>The getMapObject method</strong></h3>
<p>As stated in the documentation, the <code>getMapObject</code> method returns the MapLibre GL JS Map object after initialization.</p>
<p>To me, this reads as, 'If we cannot solve your problems, here is the map; do as you please'—in other words, exactly what I needed.</p>
<p>You might wonder, 'What can you do with this?' Well, in this case, you can take control of the map instance using a Map Initialized Dynamic Action and operate with it using all the features offered by the library itself that are not wrapped in the APEX JavaScript API implementation.</p>
<p>For example, you can fly to a certain location on the map with just the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> map = apex.region(<span class="hljs-string">"airportMap"</span>).getMapObject();
map.flyTo({
    <span class="hljs-attr">center</span>: [<span class="hljs-number">0</span>, <span class="hljs-number">0</span>], 
    <span class="hljs-attr">zoom</span>: <span class="hljs-number">11</span>, 
    <span class="hljs-attr">speed</span>: <span class="hljs-number">0.2</span>,
    <span class="hljs-attr">curve</span>: <span class="hljs-number">1</span>
});
</code></pre>
<p>The official documentation can be found <a target="_blank" href="https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/">here</a>.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Developer code that uses the MapLibre API may not be forward compatible if the MapLibre API changes</div>
</div>

<h2 id="heading-the-actual-solution">The actual solution</h2>
<p>Given that there is no native way to influence the creation of markers in APEX, the solution was clear to me: I would need to create my own markers.</p>
<p>Here’s the ingredient list:</p>
<ul>
<li><p>A collection containing at least the ID, latitude, and longitude of the points</p>
</li>
<li><p>A hidden item computed with a JSON string from the collection to read the points’ data for adding the markers to the map object.</p>
</li>
<li><p>A native Map Region</p>
</li>
<li><p>An AJAX Callback Process to update the collection when the drag ends</p>
</li>
<li><p>A 'Map Initialized' Dynamic Action to load my draggable markers with custom JavaScript</p>
</li>
<li><p>Optionally, you can include a report on top of the collection.</p>
</li>
</ul>
<h3 id="heading-the-collection">The collection</h3>
<p>Just a collection—nothing too complicated here. In this example, I am using the Sample Airport Data from the Sample Maps APEX application and limit the result set to 5 records for simplicity:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DECLARE</span>
    l_query <span class="hljs-built_in">varchar2</span>(<span class="hljs-number">4000</span>);
<span class="hljs-keyword">BEGIN</span>
    l_query := q<span class="hljs-string">'!
        select
            ID,
            nvl(
                to_number (
                    JSON_VALUE (geojson_result, '</span>$.coordinates[<span class="hljs-number">0</span>]<span class="hljs-string">')
                ),0) lat,
            nvl(
                to_number (
                    JSON_VALUE (geojson_result, '</span>$.coordinates[<span class="hljs-number">1</span>]<span class="hljs-string">')
                ),0) lng, 
            IATA_CODE,
            AIRPORT_TYPE,
            AIRPORT_NAME,
            CITY
        from (
            select a.*, 
                SDO_UTIL.TO_GEOJSON (geometry) AS geojson_result
            FROM EBA_SAMPLE_MAP_AIRPORTS a
            where city = '</span>ANCHORAGE<span class="hljs-string">'
            and rownum &lt; 6
        )!'</span>;

    APEX_COLLECTION.CREATE_COLLECTION_FROM_QUERY_B (
        p_collection_name =&gt; 'MAP_MARKERS',
        p_truncate_if_exists =&gt; 'YES',
        p_query =&gt; l_query
     );
<span class="hljs-keyword">END</span>;
</code></pre>
<h3 id="heading-the-computation">The Computation</h3>
<p>In order to create markers, you will need information to populate the markers’ attributes. This information will be read in the JavaScript section from a JSON file. In my case, I placed this data in a hidden item and computed it after the collection, using the collection sequence as an ID as it is required for the <code>UPDATE_MEMBER_ATTRIBUTE</code> procedure.</p>
<p>Here’s my SQL query (returning a single value) computation that generates the JSON in a format adapted from the official example and stores it in the hidden item <code>P5_JSON</code>:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span>
    JSON_OBJECT (
        <span class="hljs-string">'features'</span> <span class="hljs-keyword">VALUE</span> JSON_ARRAYAGG (
            JSON_OBJECT (
                <span class="hljs-string">'id'</span> <span class="hljs-keyword">VALUE</span> seq_id,
                <span class="hljs-string">'cssClasses'</span> <span class="hljs-keyword">VALUE</span> <span class="hljs-string">'fa fa-2x fa-map-marker u-color-1-text'</span>,
                <span class="hljs-string">'geometry'</span> <span class="hljs-keyword">VALUE</span> JSON_OBJECT (
                    <span class="hljs-string">'type'</span> <span class="hljs-keyword">VALUE</span> <span class="hljs-string">'Point'</span>,
                    <span class="hljs-string">'coordinates'</span> <span class="hljs-keyword">VALUE</span> JSON_ARRAY (
                       c002, c003
                    )
                )
            )
        )
    ) <span class="hljs-keyword">AS</span> jstr
<span class="hljs-keyword">from</span> apex_collections
<span class="hljs-keyword">where</span> collection_name = <span class="hljs-string">'MAP_MARKERS'</span>
</code></pre>
<h3 id="heading-the-map-region">The map region</h3>
<p>The map region is, in my case, simply a map region—not too complicated. However, be sure to set a static ID for the map region, in my case, <code>airportMap</code>.</p>
<p>Since at least one layer is mandatory for the region and this layer wasn’t needed for my purposes, I opted to pass a query that retrieves no data from the database to conserve computing resources.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727647953209/a50e3ad8-df48-446a-9a03-14d0fd466a45.png" alt="Oracle APEX - Fake query in map region to return no rows" class="image--center mx-auto" /></p>
<p>This will render and empty map of the world, but feel free to customize it to fit your needs.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727648109284/78ec4e5a-abda-4d6d-bde8-dff9ce7b628e.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-ajax-callback-process">The AJAX callback process</h3>
<p>Once again, there’s no magic—just an AJAX Callback process that executes some PL/SQL code to update the collection member with the new coordinates.</p>
<pre><code class="lang-sql">APEX_COLLECTION.UPDATE_MEMBER_ATTRIBUTE (
    p_collection_name   =&gt; 'MAP_MARKERS',
    p_seq               =&gt; apex_application.g_x01,
    p_attr_number              =&gt; 2,
    p_attr_value              =&gt; apex_application.g_x02
);


APEX_COLLECTION.UPDATE_MEMBER_ATTRIBUTE (
    p_collection_name   =&gt; 'MAP_MARKERS',
    p_seq               =&gt; apex_application.g_x01,
    p_attr_number              =&gt; 3,
    p_attr_value              =&gt; apex_application.g_x03
);
</code></pre>
<h3 id="heading-creating-markers-the-actual-magic">Creating Markers: The Actual Magic</h3>
<p>The final step involves a block of JavaScript that will be triggered by the <strong><em>Map Initialized</em></strong> component event. I created a Dynamic Action and configured the <strong><em>When</em></strong> section attributes as shown below, ensuring that the correct map region is selected:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727810596168/457d4e40-dca4-4f7e-a3a2-bd8b9ac24605.png" alt="Oracle APEX - Dynamic Action Configuration" class="image--center mx-auto" /></p>
<p>Next, create an <strong><em>Execute JavaScript Code</em></strong> True Action with the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Retrieve the MapLibre map object from the APEX region</span>
<span class="hljs-keyword">let</span> map = apex.region(<span class="hljs-string">"airportMap"</span>).getMapObject();

<span class="hljs-comment">// Parse the JSON string stored in the hidden item P5_JSON</span>
<span class="hljs-keyword">let</span> geojson = <span class="hljs-built_in">JSON</span>.parse($v(<span class="hljs-string">"P5_JSON"</span>));

<span class="hljs-comment">// Function to handle the drag end event of markers</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">onDragEnd</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Get the longitude and latitude of the marker after dragging</span>
    <span class="hljs-keyword">const</span> lngLat = <span class="hljs-built_in">this</span>.getLngLat();
    <span class="hljs-keyword">const</span> element = <span class="hljs-built_in">this</span>.getElement(); <span class="hljs-comment">// Get the marker element</span>

    <span class="hljs-comment">// Send an AJAX request to update the location in the database</span>
    apex.server.process(<span class="hljs-string">'UPDATE_LOCATION'</span>, {                             
        <span class="hljs-attr">x01</span>: element.dataset.id, <span class="hljs-comment">// Marker ID</span>
        <span class="hljs-attr">x02</span>: lngLat.lng,        <span class="hljs-comment">// Updated longitude</span>
        <span class="hljs-attr">x03</span>: lngLat.lat         <span class="hljs-comment">// Updated latitude</span>
    }, {
        <span class="hljs-attr">success</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{             
            <span class="hljs-comment">// Refresh the collection report on success (Optional)</span>
            apex.region(<span class="hljs-string">'markerReport'</span>).refresh();
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Location updated in collection"</span>);
        },
        <span class="hljs-attr">dataType</span>: <span class="hljs-string">"text"</span> <span class="hljs-comment">// Specify the response type (plain text)</span>
    });
}

<span class="hljs-comment">// Loop through each feature in the GeoJSON data to create markers</span>
geojson.features.forEach(<span class="hljs-function"><span class="hljs-params">marker</span> =&gt;</span> {
    <span class="hljs-comment">// Create a new div element for the marker</span>
    <span class="hljs-keyword">const</span> el = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
    el.className = <span class="hljs-string">"maplibregl-marker maplibregl-marker-anchor-center"</span>; <span class="hljs-comment">// Set marker classes</span>
    el.dataset.id = marker.id; <span class="hljs-comment">// Set the marker ID as a data attribute</span>

    <span class="hljs-comment">// Create a span element for additional marker styling</span>
    <span class="hljs-keyword">const</span> chd = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"span"</span>);
    chd.className = marker.cssClasses; <span class="hljs-comment">// Set CSS classes from the marker data</span>
    el.appendChild(chd); <span class="hljs-comment">// Append the span to the marker element</span>

    <span class="hljs-comment">// Create a new draggable marker and add it to the map</span>
    <span class="hljs-keyword">new</span> maplibregl.Marker({ <span class="hljs-attr">draggable</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">element</span>: el })
        .setLngLat(marker.geometry.coordinates) <span class="hljs-comment">// Set the initial position of the marker</span>
        .addTo(map) <span class="hljs-comment">// Add the marker to the map</span>
        .on(<span class="hljs-string">"dragend"</span>, onDragEnd); <span class="hljs-comment">// Attach the drag end event handler</span>
});

<span class="hljs-comment">// Center the map on the last marker's coordinates</span>
<span class="hljs-keyword">if</span> (geojson.features.length &gt; <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">const</span> lastCoordinates = geojson.features[geojson.features.length - <span class="hljs-number">1</span>].geometry.coordinates; <span class="hljs-comment">// Get last marker coordinates</span>
    map.flyTo({ <span class="hljs-attr">center</span>: lastCoordinates, <span class="hljs-attr">zoom</span>: <span class="hljs-number">11</span> }); <span class="hljs-comment">// Fly to the last marker's position</span>
}
</code></pre>
<h2 id="heading-the-result">The result</h2>
<p>As you can see, even if APEX doesn't support certain features declaratively, it provides the tools necessary to solve your problems creatively. With a bit of ingenuity, the sky is the limit!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727811570297/f9495a36-5d5b-4b53-995b-c386bb5e0c85.gif" alt class="image--center mx-auto" /></p>
<p>Enjoy Life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX - Limiting text lines with native classes in Oracle APEX]]></title><description><![CDATA[When working with Oracle APEX, one of the joys (and occasional challenges) is finding simple, elegant solutions to unique client requirements. Recently, I came across an interesting use case that I thought would be worth sharing.
The Challenge
The re...]]></description><link>https://blog.lucashir.eu/oracle-apex-limiting-text-lines-with-native-classes-in-oracle-apex</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-limiting-text-lines-with-native-classes-in-oracle-apex</guid><category><![CDATA[orclapex]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Thu, 26 Sep 2024 10:30:37 GMT</pubDate><content:encoded><![CDATA[<p>When working with <strong>Oracle APEX</strong>, one of the joys (and occasional challenges) is finding simple, elegant solutions to unique client requirements. Recently, I came across an interesting use case that I thought would be worth sharing.</p>
<h3 id="heading-the-challenge">The Challenge</h3>
<p>The requirement was pretty straightforward: we needed to display a block of text, but limit the number of characters or lines visible, with a button that allows the user to toggle between viewing the full text and collapsing it back to the limited version.</p>
<p>This kind of feature is great for improving user experience on pages where long text descriptions can clutter the interface. It also gives users more control over how much information they want to see at a glance.</p>
<h3 id="heading-the-first-step-towards-a-solution">The first step towards a solution</h3>
<p>Luckily, <strong>Oracle APEX's Universal Theme</strong> made this much easier than I anticipated. There’s a native CSS class that can help us handle text truncation: The <code>u-lineclamp-N</code> class will limit the displayed lines to the number specified in the class, ranging from 1 to 5.</p>
<p>You can find the official documentation <a target="_blank" href="https://apex.oracle.com/pls/apex/r/apex_pm/ut/content-modifiers">here</a>.</p>
<p>Let's showcase this with a simple example. Imagine a classic report like the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727341930796/01d0833e-9901-4dca-97e9-2f203f7554b5.png" alt="Oracle APEX - Classic Report with long test column as a employee's bio" class="image--center mx-auto" /></p>
<p>As you can see, excessive text can disrupt the user experience. As an alternative, we can limit the number of visible lines in a block of text to two, which can be easily achieved using the following code in an HTML Expression in a report column:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"u-lineclamp-2"</span>&gt;</span>#EMP_BIO#<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
</code></pre>
<p>This simple class ensures that only two lines of text are displayed initially, with the rest hidden, regardless of screen size. This is where the added value lies.</p>
<p>The result may be a more compact report that visually simplifies finding the right record in the table:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727342405889/16d10218-341a-45af-a9c0-a570f8179384.gif" alt class="image--center mx-auto" /></p>
<p>Now that we have limited the number of lines, we might consider giving the user control over displaying the full text.</p>
<h3 id="heading-adding-expandcollapse-functionality">Adding Expand/Collapse Functionality</h3>
<p>Using a simple piece of JavaScript, we can technically solve the problem by toggling classes in the previously mentioned <code>&lt;span&gt;</code>. In this case, we replace <code>u-lineclamp-2</code> with a non-existent one, such as <code>no-line-clamp</code>. jQuery offers a solution out of the box; here’s the basic idea:</p>
<pre><code class="lang-xml">$("CSS_Selector").toggleClass('u-lineclamp-2 no-line-clamp')
</code></pre>
<p>This function will switch the specified classes on the element in the selector, displaying the full text or hiding it again, regardless of screen size.</p>
<p>The simplest way to incorporate this code is once again in the HTML expression of the report column.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span> 
    <span class="hljs-attr">class</span>=<span class="hljs-string">"u-lineclamp-2"</span>
    <span class="hljs-attr">onclick</span>=<span class="hljs-string">"$(this).toggleClass('u-lineclamp-2 no-line-clamp');"</span>&gt;</span>
    #EMP_BIO#
<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
</code></pre>
<p>As you can see, with two simple lines of code, the user experience can increase dramatically.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727346415863/25eefe3a-f60f-4ab4-ab8d-ec6ea2a0e37d.gif" alt="Animated Gift to demonstrate how to expand and collapse text in a classic report in oracle APEX" class="image--center mx-auto" /></p>
<p>Now it's up to you to trigger that action from a better position or style the span element to clearly indicate to the user that the text is clickable.</p>
<h3 id="heading-final-thoughts">Final Thoughts</h3>
<p>This approach leverages the built-in classes of Oracle APEX's Universal Theme, making it both efficient and clean. There's no need to reinvent the wheel or write complex custom CSS—the APEX Team has already done that for you! :)</p>
<p>Enjoy life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX - Native Nested Report with Template Directives]]></title><description><![CDATA[I've frequently encountered the need for nested reports in various projects. Often, the solution required a third-party plugin, leading to the idea being dropped altogether.
While Oracle APEX offers a native solution with Master-Detail reports, we ca...]]></description><link>https://blog.lucashir.eu/oracle-apex-native-nested-report-with-template-directives</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-native-nested-report-with-template-directives</guid><category><![CDATA[orclapex]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Wed, 21 Aug 2024 08:44:01 GMT</pubDate><content:encoded><![CDATA[<p>I've frequently encountered the need for nested reports in various projects. Often, the solution required a third-party plugin, leading to the idea being dropped altogether.</p>
<p>While Oracle APEX offers a native solution with Master-Detail reports, we can agree that it's not the most user-friendly or visually appealing approach.</p>
<p>Recently, I discovered a straightforward method to display nested data inline for a master record. Before diving into the solution using template directives or HTML expressions in report columns, let’s revisit the old, less attractive way of doing this in APEX.</p>
<h2 id="heading-ugly-result-simple-way">Ugly Result Simple Way</h2>
<p>The most basic solution to your problem is to leverage SQL by using the LISTAGG aggregation function. This allows you to concatenate values separated by commas, creating what we might call a 'nested column.'</p>
<p>Here’s a simple example of what can be achieved quickly and easily, though it's not the most visually appealing solution:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> e <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span> 
        deptno,
        <span class="hljs-keyword">listagg</span> (ename || <span class="hljs-string">' ('</span> || JOB || <span class="hljs-string">')'</span>, <span class="hljs-string">', '</span>) emps
    <span class="hljs-keyword">from</span> emp
    <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> deptno
)
<span class="hljs-keyword">select</span> 
    dname department, 
    emps employees
<span class="hljs-keyword">from</span> dept d 
<span class="hljs-keyword">join</span> e <span class="hljs-keyword">on</span> e.deptno = d.deptno
</code></pre>
<p>If we create a classic report using this query, APEX will deliver a functional report out of the box that will, hopefully, get the job done:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724179130667/847570cd-fee2-4f2d-92f4-fd9af987c24e.png" alt="Classic Report with Nested Column" class="image--center mx-auto" /></p>
<h2 id="heading-simple-result-ugly-way">Simple Result Ugly Way</h2>
<p>It quickly becomes clear that the result isn't ideal from a user interface perspective, if nothing else. My second attempt to address the issue involved adding some custom HTML tags directly into the query. Keep in mind that, at the time, HTML expressions weren't as widely available as they are today.</p>
<p>Here’s a potentially improved query:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> e <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span> 
        deptno,
        <span class="hljs-string">'&lt;ul&gt;'</span> ||
            <span class="hljs-keyword">listagg</span> ( <span class="hljs-string">'&lt;li&gt;'</span> || ename || <span class="hljs-string">' ('</span> || JOB || <span class="hljs-string">') &lt;/li&gt;'</span>, <span class="hljs-string">''</span>) ||
        <span class="hljs-string">'&lt;/ul&gt;'</span> emps 
    <span class="hljs-keyword">from</span> emp
    <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> deptno
)
<span class="hljs-keyword">select</span> 
    dname department, 
    emps employees
<span class="hljs-keyword">from</span> dept d 
<span class="hljs-keyword">join</span> e <span class="hljs-keyword">on</span> e.deptno = d.deptno
</code></pre>
<p>This method requires lowering the security settings on the column to avoid escaping special characters. As a result, it's far from a recommended approach, especially in APEX versions that already support template directives. The outcome:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724179338555/d86caa8c-bbe9-4698-8dd6-199765678852.png" alt="Classic Report WIth Unordered List" class="image--center mx-auto" /></p>
<h2 id="heading-improved-result-simple-way">Improved Result Simple Way</h2>
<p>With the introduction of HTML Expressions and Template Directives, this problem can now be solved in an elegant way. There's no longer a need to hardcode HTML in queries, which makes them difficult to read and maintain, nor is there a need to disable default security features.</p>
<p>For the example above, the Loop Clause is a perfect fit. We can revert to the query from the first example and simply create the unordered list in the HTML Expression attribute of that column, like this:</p>
<pre><code class="lang-xml">   <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {loop "," TAGS/}
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>&amp;APEX$ITEM.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        {endloop/}
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
</code></pre>
<p>Alternatively, using the exact same technique, you can create a table within that column:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">table</span>&gt;</span>
    {loop "," EMPLOYEES/}
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>&amp;APEX$ITEM.<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    {endloop/}
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<p>The result should be exactly the same as before but achieved in a native and secure way within Oracle APEX.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724221401801/b2c8c499-0a21-4072-b804-79ae60102fc9.png" alt="Classic Report with Nested Table Column" class="image--center mx-auto" /></p>
<h2 id="heading-improved-result-improved-way">Improved Result Improved Way</h2>
<p>Assuming you're still following along, you'll notice that the user interface isn't ideal in the previous examples.</p>
<p>In each case, I wanted to aggregate two columns (Name and Title) into the details column, but it wasn’t possible to format each value separately.</p>
<p>Here’s the solution I found, still using native APEX functionalities. In this approach, I concatenate the Employee Name and Title, separated by a <code>:</code>. The result can be interpreted as a Key-Value detailed column, formatted like this:</p>
<blockquote>
<p>key1:value1,key2:value2,keyN:valueN</p>
</blockquote>
<p>Here’s the query:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">with</span> e <span class="hljs-keyword">as</span> (
    <span class="hljs-keyword">select</span> 
        deptno,
        <span class="hljs-keyword">listagg</span> (ename || <span class="hljs-string">':'</span> || JOB, <span class="hljs-string">','</span>) emps
    <span class="hljs-keyword">from</span> emp
    <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> deptno
)
<span class="hljs-keyword">select</span> 
    dname department, 
    emps employees
<span class="hljs-keyword">from</span> dept d 
<span class="hljs-keyword">join</span> e <span class="hljs-keyword">on</span> e.deptno = d.deptno
</code></pre>
<p>Here's the trick: by using a combination of template directives with <code>loops</code>, <code>case</code> and <code>with</code>, we can split the record twice to apply different styling to each piece of information.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">dl</span>&gt;</span>
{loop "," EMPLOYEES/}
    <span class="hljs-tag">&lt;<span class="hljs-name">dt</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"padding-sm"</span>&gt;</span>
    {loop ":" APEX$ITEM/}
        {case APEX$I/}
            {when 1/}
                &amp;APEX$ITEM.
            {when 2/}
                {with/}
                    LABEL:=TITLE
                    VALUE:=&amp;APEX$ITEM.
                    LABEL_DISPLAY:=N
                    STYLE:=t-Badge--subtle
                    SHAPE:=t-Badge--circle
                {apply THEME$BADGE/}
        {endcase/}
    {endloop/}
    <span class="hljs-tag">&lt;/<span class="hljs-name">dt</span>&gt;</span>
{endloop/}
<span class="hljs-tag">&lt;<span class="hljs-name">dl</span>&gt;</span>
</code></pre>
<p>The result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724228210593/d97009f4-79bc-4685-b42e-0ad4e01deb8e.png" alt="Classic Report with Nested Column with two values" class="image--center mx-auto" /></p>
<p>Wow! You might be wondering what just happened. Here’s a quick explanation:</p>
<p>According to the documentation, there are two substitution strings available in the <code>Loop</code> directive:</p>
<ul>
<li><p><strong>APEX$ITEM</strong>: Represents the value of the current item in the list.</p>
</li>
<li><p><strong>APEX$I</strong>: Indicates the 1-based index of the current item in the list.</p>
</li>
</ul>
<p>For more information about template directives, you can refer to the documentation <a target="_blank" href="https://docs.oracle.com/en/database/oracle/apex/23.1/htmdb/using-template-directives.html#GUID-7B407C82-7469-4C02-811C-E43380D1B73C">here</a>.</p>
<p>What isn’t explicitly mentioned in the documentation is that you can loop again and use the <code>APEX$ITEM</code> substitution in the second loop to re-split the value using a different separator, such as <code>:</code>.</p>
<p>By combining a case directive with the <code>APEX$I</code> substitution, you can differentiate between the "Key" (value at index 1) and the "Value" (value at index 2), allowing you to apply different styling.</p>
<p>In my case, I simply print the <code>ENAME</code> while applying a badge template to the <code>TITLE</code> column using the <code>WITH</code> clause.</p>
<h2 id="heading-colorful-templating">Colorful Templating</h2>
<p>If you weren’t aware of the <code>APEX$I</code> substitution, here’s another quick use for it. Although the syntax of template directives is quite limited, you can still leverage the Index substitution to apply a color class to each element in a visually appealing way. Note the <code>u-color-&amp;APEX$I.</code> syntax in the STYLE clause.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">dl</span>&gt;</span>
{loop "," EMPLOYEES/}
    <span class="hljs-tag">&lt;<span class="hljs-name">dt</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"padding-sm"</span>&gt;</span>
        {with/}
            LABEL:=EMPLOYEE
            VALUE:=&amp;APEX$ITEM.
            LABEL_DISPLAY:=N
            STYLE:=t-Badge--subtle u-color-&amp;APEX$I.
            SHAPE:=t-Badge--circle
        {apply THEME$BADGE/}
    <span class="hljs-tag">&lt;/<span class="hljs-name">dt</span>&gt;</span>
{endloop/}
<span class="hljs-tag">&lt;<span class="hljs-name">dl</span>&gt;</span>
</code></pre>
<p>Here's a simplified example to illustrate the concept:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724229132252/f6f92844-f65a-42d5-ae97-08bbb4d9586b.png" alt class="image--center mx-auto" /></p>
<p>Enjoy Life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX - Post-it Notes with Card Report]]></title><description><![CDATA[I’ve set myself a challenge today: creating a visually appealing post-it notes report in Oracle APEX with minimal coding.
After some initial research and not finding exactly what I needed, I decided to tackle the problem myself. As I've mentioned bef...]]></description><link>https://blog.lucashir.eu/oracle-apex-post-it-notes-with-card-report</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-post-it-notes-with-card-report</guid><category><![CDATA[Oracle]]></category><category><![CDATA[orclapex]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Wed, 07 Aug 2024 10:51:37 GMT</pubDate><content:encoded><![CDATA[<p>I’ve set myself a challenge today: creating a visually appealing post-it notes report in Oracle APEX with minimal coding.</p>
<p>After some initial research and not finding exactly what I needed, I decided to tackle the problem myself. As I've mentioned before, I prefer to use as many native classes as possible and aim to create sustainable code that remains intact through any theme updates. This approach involves avoiding hardcoded values for sizes, colors, or other CSS properties.</p>
<p>Here is the result.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723025492285/5c1f9999-e60f-4fbb-9cf7-dca2d2264026.png" alt="Oracle APEX - Post-It Notes Card Report" class="image--center mx-auto" /></p>
<p>And here are the steps:</p>
<ol>
<li>Make sure your Card Region has a Static ID. In my example, <code>card-post-it</code>.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723027171514/51922782-bf2a-4331-90e5-023ff53d4e3f.png" alt class="image--center mx-auto" /></p>
<ol start="2">
<li>In your Card Report, set the CSS Classes attribute to one of the color classes from the palette. For this case, use <code>u-color-6</code>.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723026665358/8bda0bba-8e88-4460-85fb-7f17ade27a38.png" alt="Oracle APEX - Card Report Attributes Screenshot" class="image--center mx-auto" /></p>
<ol start="3">
<li>Add the following custom CSS class in Theme Roller:</li>
</ol>
<pre><code class="lang-css"><span class="hljs-comment">/* Post-it Notes CSS */</span>
<span class="hljs-selector-id">#card-post-it</span> <span class="hljs-selector-class">.a-CardView-items</span> {
  <span class="hljs-attribute">--a-cv-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0px</span> <span class="hljs-number">0px</span> <span class="hljs-number">0px</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-selector-id">#card-post-it</span> <span class="hljs-selector-class">.a-CardView</span> {
    <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid <span class="hljs-built_in">var</span>(--u-color-<span class="hljs-number">36</span>);
}

<span class="hljs-selector-id">#card-post-it</span> <span class="hljs-selector-class">.a-CardView</span><span class="hljs-selector-pseudo">:before</span> {
  <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">bottom</span>: -<span class="hljs-number">2px</span>;
  <span class="hljs-attribute">right</span>: -<span class="hljs-number">2px</span>;       
  <span class="hljs-attribute">border-top</span>: <span class="hljs-number">20px</span> solid <span class="hljs-built_in">var</span>(--u-color-<span class="hljs-number">36</span>);
  <span class="hljs-attribute">border-right</span>: <span class="hljs-number">20px</span> solid <span class="hljs-built_in">var</span>(--a-cv-background-color); 
}
</code></pre>
<p>To improve the appearance of the notes, follow these steps:</p>
<ul>
<li><p><strong>Remove the Card Shadow:</strong> To remove the card shadow, override the <code>--a-cv-shadow</code> variable with <code>0 0px 0px 0px rgba(0, 0, 0)</code>. This change applies only to this report by using the Static ID <code>#card-post-it .a-CardView-items</code>.</p>
</li>
<li><p><strong>Set the Card Border:</strong> Adjust the border of the cards to a darker version of the selected color by using the CSS variable <code>var(--u-color-36)</code>. Here's the breakdown of the color palette:</p>
<ul>
<li><p><code>u-color-6</code> is the base color.</p>
</li>
<li><p><code>u-color-21</code> is a lighter version of the base color.</p>
</li>
<li><p><code>u-color-36</code> is a darker version of the base color.</p>
</li>
</ul>
</li>
<li><p><strong>Apply the Folded Effect:</strong> For the folded effect on the bottom right corner, use CSS variables to ensure color adjustments don't disrupt the design. In the top section, apply the dark color (<code>--u-color-36</code>), while in the right section, use the <code>--a-cv-background-color</code>. This approach keeps the design consistent with any color changes.</p>
</li>
</ul>
<p>You can learn more about colors in the Universal Theme<a target="_blank" href="https://apex.oracle.com/pls/apex/r/apex_pm/ut/color-and-status-modifiers"><code>here</code></a>.</p>
<p>Enjoy Life.</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX - Multi-Social Sign-In Provider]]></title><description><![CDATA[When working with publicly exposed applications, security should always be a top priority for developers. The more security responsibilities you can delegate, the better. One of the key aspects to delegate is authentication.
In this post, I will expl...]]></description><link>https://blog.lucashir.eu/oracle-apex-multi-social-sign-in-provider</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-multi-social-sign-in-provider</guid><category><![CDATA[orclapex]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Mon, 05 Aug 2024 10:59:10 GMT</pubDate><content:encoded><![CDATA[<p>When working with publicly exposed applications, security should always be a top priority for developers. The more security responsibilities you can delegate, the better. One of the key aspects to delegate is authentication.</p>
<p>In this post, I will explore the integration of multiple public authentication providers, which can add flexibility to your application. This allows users to log in using their Google or Microsoft accounts, depending on their preference or existing credentials.</p>
<p>Delegating the authentication process means you won't need to save or handle any user credentials. There's no need for registration or password reset flows—all of this comes out of the box in Oracle APEX using the industry-standard OAuth 2.0.</p>
<p>A few things to consider:</p>
<ul>
<li><p>You’ll need to implement various identity providers to accommodate the majority of your potential users (not covered in this post).</p>
</li>
<li><p>A landing page will be required for users to choose which provider to use.</p>
</li>
<li><p>Ensure the "Switch in Session" option is enabled for all authentication schemas.</p>
</li>
</ul>
<h2 id="heading-multiple-identity-providers">Multiple Identity Providers</h2>
<p>As you might already know, Oracle APEX provides a native and declarative way to integrate with any identity provider that follows the OAuth 2.0 standard. I won’t go into detail on how to set this up, as there's plenty of documentation available on the topic. The process is quite similar for each provider:</p>
<ol>
<li><p>Register with the provider’s development portal.</p>
</li>
<li><p>Create an API key to consume services using your APEX callback URL.</p>
</li>
<li><p>Add the credentials to your workspace credentials.</p>
</li>
<li><p>Configure the authentication schemas in your application.</p>
</li>
<li><p>Make sure the scheme name is simple to avoid complications later on. For example, use <code>GOOGLE</code> for Google or <code>AZURE</code> for Microsoft, rather than something longer like 'Google Identity Provider.</p>
</li>
</ol>
<p>Optionally, if you have multiple applications in the same workspace, you might consider creating a master application to manage authentication—either by sharing the authentication cookie or by subscribing to the schemas in other apps.</p>
<p>By default, one of the configured authentication schemes will be active. When you run your application, users may unexpectedly land on the identity provider’s login page, which can be confusing. For example, they might request access to your application and be redirected to the Google or Microsoft login page without prior notice.</p>
<p>We’ll address this issue in the next section, but first, ensure that the 'Switch in Session' attribute is enabled for all your configured authentication schemes. You can find this option in the Login Processing section of your authentication scheme settings.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722851623424/446da6e5-634c-4ce7-b4a0-adc91ffce0c5.png" alt="Oracle APEX - Authentication Scheme Attributes" class="image--center mx-auto" /></p>
<p>This option is critical in the process because, if enabled, it allows the current session's authentication scheme to be changed by passing <code>APEX_AUTHENTICATION=scheme_name</code> in a URL's request parameter. I will explain how this works in the next section.</p>
<h2 id="heading-provider-decision-landing-page">Provider decision landing page</h2>
<p>The first important aspect to consider is the user authentication flow. The logical approach is to present a decision page where users can choose which provider to use. With a button click, users should communicate their choice to APEX.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722850947676/4e76b573-35a2-4a47-9d51-bd9e1b099f30.png" alt="Oracle APEX - Login Landing Page" class="image--center mx-auto" /></p>
<p>For my Climbing Club application, I used the following approach:</p>
<ol>
<li><p><strong>Create a New Public Page</strong>: Design a new page with all the information you need for user decisions.</p>
</li>
<li><p><strong>Set the New Decision Page as the Home Page</strong>: Go to Shared Components &gt; User Interfaces &gt; Attributes &gt; Home URL and set your new decision page as the home page of your application.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722854497397/558c7119-2d98-412c-a0c4-02b1ccb3041f.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>Create a <strong><em>Before Header Branch</em></strong> to redirect users to the <strong>Authenticated</strong> home page of your application. Under <strong>Security</strong>, set the Authorization Scheme to <code>Must Not Be Public User</code>. This ensures that users are directed to the page you want them to visit once authenticated, rather than remaining on the decision landing page.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722855203274/5c3ff7dc-0a3d-4add-8e61-045de54d454c.png" alt="Oracle APEX - Branch Creation in Page Builder" class="image--center mx-auto" /></p>
<ol>
<li><p>On the landing page, create a button for each authentication scheme.</p>
<ul>
<li><p>Set the button action to <code>Redirect to Page in this Application.</code></p>
</li>
<li><p>Again, for the target page, select the page you want users to visit once they are authenticated.</p>
</li>
<li><p>In the 'Request' section, set the Special Request in the format <code>APEX_AUTHENTICATION=&lt;Authentication Scheme Name&gt;</code> as mentioned in the previous section.</p>
</li>
</ul>
</li>
</ol>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722854973517/bb90fd53-9fb4-42d4-abf1-00f56f5c7853.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Remember to use simple names for your schemes, as you will reference them here.</div>
</div>

<p>With these simple steps, your authentication flow should be clearer for users and flexible enough to allow them to select the identity provider that best fits their needs.</p>
<p>Enjoy Life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX - Native Equal Height Regions in the Universal Theme]]></title><description><![CDATA[I've realized that I can be a bit of a perfectionist, especially when it comes to working with helper classes in Oracle APEX's Universal Theme.
I encountered a recurring issue that always bothered me, but I discovered it's actually easy to fix using ...]]></description><link>https://blog.lucashir.eu/oracle-apex-native-equal-height-regions-in-the-universal-theme</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-native-equal-height-regions-in-the-universal-theme</guid><category><![CDATA[Oracle]]></category><category><![CDATA[orclapex]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Fri, 02 Aug 2024 10:48:48 GMT</pubDate><content:encoded><![CDATA[<p>I've realized that I can be a bit of a perfectionist, especially when it comes to working with helper classes in Oracle APEX's Universal Theme.</p>
<p>I encountered a recurring issue that always bothered me, but I discovered it's actually easy to fix using native CSS helper classes.</p>
<p>The challenge occurs when trying to set two or more regions within the same row to have equal heights. Here’s a typical example.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722430415102/4dfe4354-3615-4359-9964-d6b5d5aeee9a.png" alt="Oracle APEX - 3 Regions in a row where the element heights is not even." class="image--center mx-auto" /></p>
<p>Even though hardcoding heights to a fixed value with CSS can often create more problems than it solves, this can be done easily in APEX. You can do it natively and declaratively by using the standard region template—simply by setting the Body Height attribute under Template Options:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722430558191/eb1ab8cf-123b-497d-81b2-feb87db05048.png" alt="Oracle APEX - Template Options for standar region template" class="image--center mx-auto" /></p>
<p>Alternatively, you can use native CSS height helpers in APEX, such as <code>hamount</code>, where <code>amount</code> spans from 10 to 800 in increments of 10.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722430721150/cf5d3cef-f92b-4856-8163-d4e9391c1ff3.png" alt="Oracle APEX - Appearance Attributes in page builder" class="image--center mx-auto" /></p>
<p>As mentioned earlier, this solution is not optimal for different screen sizes or when you don't control the amount of content in the regions.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722431603964/91a87ab3-48e7-4bc4-86e8-cf998c37315d.png" alt="Oracle APEX - Non Optimal solution for region height. " class="image--center mx-auto" /></p>
<p>After searching for a better approach, I discovered that this issue can be easily resolved in under 30 seconds by using native CSS classes in the Universal Theme.</p>
<p>To achieve this, we need to treat the element as a flex container and its children as flex items. To do this, set the Column CSS Classes attribute to <code>u-flex</code> for all the regions in the same row under the Layout section.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722432012623/a28b70c5-9d66-4047-83ab-0300c1b7594a.png" alt="Oracle APEX - Layout Attribute section" class="image--center mx-auto" /></p>
<p>Next, we need to allow the item to grow to fit the available space. There's already a native class available for this, called <code>u-flex-grow-1</code>, which should be set as the CSS Class in the Appearance section. Again, for all the regions in the row.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722432230296/d5991a4f-c60c-4854-8d1d-a74e7a69d580.png" alt="Oracle APEX - Appearance Attribute Sections in Page Builder" class="image--center mx-auto" /></p>
<p>This will equalize the heights of all the regions based on the tallest one, regardless of screen size.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722432317064/5559bbba-ed78-46f8-ad0d-157432709450.png" alt /></p>
<p>Enjoy Life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX - Custom Highlight Animation]]></title><description><![CDATA[In some cases, highlighting events in a user interface can be very useful. It’s a powerful way to inform users about what has happened after certain actions.
For instance, imagine users are required to select a shop from a multi-column Popup LOV that...]]></description><link>https://blog.lucashir.eu/oracle-apex-custom-highlight-animation</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-custom-highlight-animation</guid><category><![CDATA[Oracle]]></category><category><![CDATA[orclapex]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Fri, 02 Aug 2024 10:48:27 GMT</pubDate><content:encoded><![CDATA[<p>In some cases, highlighting events in a user interface can be very useful. It’s a powerful way to inform users about what has happened after certain actions.</p>
<p>For instance, imagine users are required to select a shop from a multi-column Popup LOV that displays the shop addresses for easier identification. If users select a shop by name, they might not immediately confirm that their selection is correct.</p>
<p>In such cases, you might use additional outputs in the Popup LOV to populate read-only items, allowing users to validate their choice.</p>
<p>However, simply updating the item values may not be as clear or effective for the user. This is why a small trick to highlight changes in the user interface can be very helpful just with a bit of custom CSS and JavaScript.</p>
<p>Here are the steps:</p>
<ol>
<li>Include the following CSS classes in your custom CSS code in Theme Roller:</li>
</ol>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> highlight {    
    50% {<span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--u-color-<span class="hljs-number">22</span>);}
    100% { <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--a-field-input-background-color); }
}
<span class="hljs-selector-class">.active</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--a-field-input-background-color);
    <span class="hljs-attribute">animation-name</span>: highlight;
    <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">1.5s</span>;
}
</code></pre>
<ol start="2">
<li><p>Add a custom CSS class (e.g., 'ihighlight') to all the items you want to highlight. You can do this in the item properties under Advance &gt; CSS classes</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722433598256/54b1182e-f91b-4f41-8326-cdcb2de794b4.png" alt class="image--center mx-auto" /></p>
<p> Create an <code>On Change</code> Dynamic Action in the item that will trigger the highlight</p>
</li>
<li><p>Add this small JavaScript snippet to the <code>True</code> action</p>
</li>
</ol>
<pre><code class="lang-javascript">$(<span class="hljs-string">'.ihighlight'</span>).removeClass(<span class="hljs-string">'active'</span>).trigger(<span class="hljs-string">'focus'</span>).select();
<span class="hljs-built_in">setTimeout</span>(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{ $(<span class="hljs-string">'.ihighlight'</span>).addClass(<span class="hljs-string">'active'</span>);}, <span class="hljs-number">100</span>);
</code></pre>
<p>The result should be something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722433715505/7e473b02-adb1-489c-b662-27c687c32121.gif" alt="Oracle APEX - Animated Gif that highlight items in yellow" class="image--center mx-auto" /></p>
<p>Enjoy Life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX  - Making Responsive Tables with Universal Theme Native Classes]]></title><description><![CDATA[In Oracle APEX, the Universal Theme offers a rich set of templates that can address most of your needs. However, there may be instances where implementing a basic feature becomes challenging.
For all edge cases, the Universal Theme provides a compreh...]]></description><link>https://blog.lucashir.eu/oracle-apex-making-responsive-tables-with-universal-theme-native-classes</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-making-responsive-tables-with-universal-theme-native-classes</guid><category><![CDATA[Oracle]]></category><category><![CDATA[#oracle-apex]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Fri, 02 Aug 2024 10:47:59 GMT</pubDate><content:encoded><![CDATA[<p>In Oracle APEX, the Universal Theme offers a rich set of templates that can address most of your needs. However, there may be instances where implementing a basic feature becomes challenging.</p>
<p>For all edge cases, the Universal Theme provides a comprehensive list of predefined classes that allow you to adjust the look and feel of your application in a uniquely sustainable way.</p>
<p>Using native classes ensures that after a Universal Theme upgrade, your application will likely remain functional, automatically inheriting any fundamental changes from the Oracle APEX team.</p>
<p>Let me illustrate this with an extreme example: If the APEX team redefines paddings tomorrow, using the native class <code>padding-sm</code> will automatically update the padding from 0.5rem to the new value defined by Oracle's UI/UX team. However, if you hardcode that value in your own CSS, it won't change, potentially causing your application to look inconsistent.</p>
<h2 id="heading-the-problem">The Problem</h2>
<p>Back to the topic, I have recently wanted to create Card-Per-Row template, with a big image on the side. As you can see below, that is possible with the Card Report in the horizontal layout.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1717425047291/71e171d0-79f3-470a-bb7e-0922e1075d79.png" alt="Oracle APEX - Horizontal Layout Card Report" class="image--center mx-auto" /></p>
<p>Apart from encountering some limitations with these template options, which are off-topic for this post and were confirmed by the Oracle APEX team (see below), I wanted to include a table-type layout inside the Card template to better present the basic information.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718962437423/4e859b98-3bcc-421a-b2f6-5dfe5a2d5b7c.png" alt="Card Report Template Limitaition. " class="image--center mx-auto" /></p>
<h2 id="heading-the-solution">The Solution</h2>
<p>Having a lot of data inside a card is probably one of those edge cases mentioned above, which is why I attempted to solve the problem using a custom yet native way.</p>
<p>With this simple approach and by using Universal Theme's native CSS helper classes, you can hide the first column with the labels on smaller screens and display an extra row with the same label instead.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w100p padding-sm"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-md-up"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-sm-down"</span>&gt;</span>Name<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"u-bold"</span>&gt;</span>&amp;ENAME.<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-md-up"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Job<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-sm-down"</span>&gt;</span>Job<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"u-bold"</span>&gt;</span>&amp;JOB.<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-md-up"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Salary<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-sm-down"</span>&gt;</span>Salary<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"u-bold"</span>&gt;</span>&amp;SAL.<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-md-up"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>Hire Date<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"hidden-sm-down"</span>&gt;</span>Hire Date<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"u-bold"</span>&gt;</span> &amp;HIREDATE.<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
</code></pre>
<p>Check the visibility classes in the documentation here for more info.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718965411351/42585f9e-32e0-4107-8804-0a8b56fd7036.png" alt="Oracle APEX Universal Theme Documenation - Grid Layout" class="image--center mx-auto" /></p>
<h2 id="heading-the-result">The Result</h2>
<p>With a bit of extra effort, you can transform your card region horizontal template into a nice-looking info card like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718964442606/27c2e94c-e58c-46d9-a86f-0a6ad971ee53.gif" alt class="image--center mx-auto" /></p>
<p>Enjoy life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX - Mastering Collapsible Regions]]></title><description><![CDATA[One of the most effective ways to learn is by helping others, and this is a practice I have embraced for the past 20 years.
The benefits are twofold: not only is it incredibly satisfying to assist someone in overcoming their challenges, but it also c...]]></description><link>https://blog.lucashir.eu/oracle-apex-mastering-collapsible-regions</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-mastering-collapsible-regions</guid><category><![CDATA[Oracle]]></category><category><![CDATA[orclapex]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Fri, 02 Aug 2024 10:22:40 GMT</pubDate><content:encoded><![CDATA[<p>One of the most effective ways to learn is by helping others, and this is a practice I have embraced for the past 20 years.</p>
<p>The benefits are twofold: not only is it incredibly satisfying to assist someone in overcoming their challenges, but it also compels you to delve into solutions for real-life problems, whether you are familiar with them or not. Not to mention that someone else's solution might surpass the one you proposed.</p>
<p>One of my sources of inspiration is the Oracle Forum. Recently, there were two questions on similar topics that I wanted to document here for the record:</p>
<ol>
<li><p>How to capture a collapsed/expanded event in a collapsible region.</p>
</li>
<li><p>How to expand or collapse all records with a single button click.</p>
</li>
</ol>
<h2 id="heading-1-capturing-collapsed-and-expanded-events">1. Capturing collapsed and expanded events</h2>
<p>If you quickly inspect the code behind the scenes in your browser when expanding or collapsing a collapsible region in Oracle APEX, you will notice that two specific CSS classes are toggled in the region container: <code>is-collapsed</code> and <code>is-expanded</code> .</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718969132123/aa823f1e-c91d-4a36-a6e5-5d1c481481c4.gif" alt class="image--center mx-auto" /></p>
<p>In my effort to always solve problems natively, declaratively or in a low code way, here was my proposed solution.</p>
<h3 id="heading-capturing-events-1-approach">Capturing Events - #1 Approach</h3>
<p>This low-code approach is based on testing whether the region has certain CSS classes. That check happens when a click on the region icon occurs.</p>
<ol>
<li><p>Create a Dynamic Action</p>
</li>
<li><p>Event: “Click”</p>
</li>
<li><p>Selection Type: “jQuery Selector”</p>
</li>
<li><p>jQuery Selector: <code>#myRegion .t-Button.t-Button--icon.t-Button--hideShow</code></p>
</li>
<li><p>Add a client-side condition to check if your region now has the <code>is-expanded</code> class.</p>
</li>
<li><p>Create your true/false action.</p>
</li>
</ol>
<p><img src="https://objectstorage.us-phoenix-1.oraclecloud.com/p/8XchFSZkjz8qO4p8uxTZOqA0LbZbAcrp1MON3Ph8P79VRQLjAIsR8S0ieDkLokBl/n/axciphqpnohg/b/forums-prod-www/o/attachments/MIAAKkni-3925-KnJunXmk" alt class="image--center mx-auto" /></p>
<p>Assuming we have an Alert as the true and false action, this would be the result:</p>
<p><img src="https://objectstorage.us-phoenix-1.oraclecloud.com/p/8XchFSZkjz8qO4p8uxTZOqA0LbZbAcrp1MON3Ph8P79VRQLjAIsR8S0ieDkLokBl/n/axciphqpnohg/b/forums-prod-www/o/attachments/sOcupSjp-8792-EnkQCqny" alt class="image--center mx-auto" /></p>
<h3 id="heading-catching-non-documented-events-2-approach">Catching Non Documented Events - #2 approach</h3>
<p>Thanks to <a target="_blank" href="https://hardlikesoftware.com/weblog/about-me/">John Snyders</a>, who in his comment pointed out a better approach to achieving a similar result using two undocumented events.</p>
<p>Here is the original code for the more-code enthusiasts:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Catch the collaps event</span>
$(<span class="hljs-string">"#myRegion"</span>).on(
    <span class="hljs-string">"collapsiblecollapse"</span>,<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"collapsed"</span>)
});
<span class="hljs-comment">// Catch the expand event</span>
$(<span class="hljs-string">"#myRegion"</span>).on(
    <span class="hljs-string">"collapsibleexpand"</span>, <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"expanded"</span>)
});
</code></pre>
<p>If you are a low-code enthusiast, here is what you can do:</p>
<ol>
<li><p>Create a Dynamic Action</p>
</li>
<li><p>Event: “Custom”</p>
</li>
<li><p>Custom Event: <code>collapsiblecollapse</code> or <code>collapsibleexpand</code></p>
</li>
<li><p>Selection Type: “jQuery Selector”</p>
</li>
<li><p>jQuery Selector: <code>#myRegion</code></p>
</li>
<li><p>Create your true/false action.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718971328534/4177d1b7-778d-497b-9d70-bf804ab17fa8.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-2-control-them-all-from-a-sigle-button">2. Control them all from a sigle button</h2>
<p>The second question was about how to control all the collapsible regions from a single control button.</p>
<p>My initial approach was to use a method similar to the previous case, where I caught the click event and triggered an extra click in the second region. While this works, it is not the most elegant or scalable solution.</p>
<p>Again, a better solution comes from the community. Thanks to Karel Ekema for pointing out that there is already a function in APEX to control the collapsible regions.</p>
<p>Unfortunately, I haven't found it in the documentation, but exploring the source code of <code>desktop_all.js</code> provides enough information to get started.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Expand the collapsible regions provided in the CSS selector.</span>
$(<span class="hljs-string">'&lt;css_selector&gt;'</span>).collapsible(<span class="hljs-string">'expand'</span>);

<span class="hljs-comment">// Collapse the collapsible regions provided in the CSS selector.</span>
$(<span class="hljs-string">'&lt;css_selector&gt;'</span>).collapsible(<span class="hljs-string">'collapse'</span>);

<span class="hljs-comment">// Toggle the status of the collapsible regions provided in the CSS selector.</span>
$(<span class="hljs-string">'&lt;css_selector&gt;'</span>).collapsible(<span class="hljs-string">'toggle'</span>);
</code></pre>
<p>Using this simple line of code, you can target all collapsible regions at once.</p>
<p>Let's try it:</p>
<ol>
<li><p><strong>Add a Custom CSS Class</strong>:</p>
<ul>
<li><p>In the "Appearance" section of attributes for all the regions you want to control, add a custom CSS class, e.g., <code>masterAll</code>.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719239610586/60ac09f6-6b68-4e97-997c-0abbaa27978b.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
<li><p><strong>Create a Button</strong>:</p>
<ul>
<li>Create a button in your application.</li>
</ul>
</li>
<li><p><strong>Create a Dynamic Action</strong>:</p>
<ul>
<li><p><strong>Event</strong>: Click</p>
</li>
<li><p><strong>Selection Type</strong>: Button</p>
</li>
<li><p><strong>Button</strong>: Select the button you have just created.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719239630315/c7d5ebe0-9c65-470b-a4cf-3e3d41f24cc5.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
<li><p><strong>Create a True Action</strong>:</p>
<ul>
<li><p><strong>Action</strong>: Execute JavaScript Code</p>
</li>
<li><p><strong>Code</strong>: <code>$('.masterAll').collapsible('toggle');</code></p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719239674192/be5226ea-0fc2-46e0-872e-08cb8116e823.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
<li><p><strong>Repeat</strong>:</p>
<ul>
<li>Repeat the above steps for the Expand/Collapse button.</li>
</ul>
</li>
</ol>
<p>This results in an easy way of controlling your collapsible regions from a single action button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719239770434/c7e1df4a-3b04-4e0c-b2a1-663a8946518d.gif" alt class="image--center mx-auto" /></p>
<p>Enjoy life!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX - Customizing Fonts]]></title><description><![CDATA[I've been experimenting with web fonts in Oracle APEX recently, and I'm amazed at how much easier it is now to set a custom font using Google Fonts.
Here are my findings on customizing fonts in the Oracle APEX Universal Theme.
Changing Font Family
Yo...]]></description><link>https://blog.lucashir.eu/oracle-apex-customizing-fonts</link><guid isPermaLink="true">https://blog.lucashir.eu/oracle-apex-customizing-fonts</guid><category><![CDATA[orclapex]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Lucas Hirschegger]]></dc:creator><pubDate>Fri, 02 Aug 2024 10:19:23 GMT</pubDate><content:encoded><![CDATA[<p>I've been experimenting with web fonts in Oracle APEX recently, and I'm amazed at how much easier it is now to set a custom font using Google Fonts.</p>
<p>Here are my findings on customizing fonts in the Oracle APEX Universal Theme.</p>
<h2 id="heading-changing-font-family">Changing Font Family</h2>
<p>You can achieve the same result using any web fonts, including your own. However, if you're using Google Fonts, just follow these simple steps:</p>
<ol>
<li><p>Look for the font you want to use <strong>- Nunito</strong> for instance - and click <strong><em>Get font</em></strong></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722590926923/405fc5b0-37f3-4131-bc01-4f493d2f0156.png" alt="Google Fonts - Font landing page screenshot" class="image--center mx-auto" /></p>
</li>
<li><p>Once you're on the selected font family's landing page, click <strong><em>Get Embed Code.</em></strong></p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722590939962/7cd0be08-983a-41e6-ae8d-6a81f073beed.png" alt="Google Fonts - Font Selected page screenshot" class="image--center mx-auto" /></p>
</li>
<li><p>From the Embed page, copy the Font URL (highlighted in yellow).</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722590950970/99be43a5-a81e-4dc9-819b-f4503f01ed21.png" alt="Google Fonts - Font embed code screenshot" class="image--center mx-auto" /></p>
</li>
<li><p>The final step is to add the Font URL to your application, so APEX can download the font file when needed. The easiest way to do this is by going to <strong>Application Builder</strong>. While editing your application, navigate to <strong>Shared Components &gt; User Interfaces &gt; CSS</strong>, and paste the URL into the <strong><em>File URLs</em></strong> section.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722590788158/32142698-be38-43b7-befd-191d204a3698.png" alt="Oracle APEX - Application builder User interface page screenshot" class="image--center mx-auto" /></p>
</li>
</ol>
<p>Now, your application will have the selected font available for use in any of its elements. If you want to apply the font globally across your application, you can set the font properties in <strong>Theme Roller</strong>. In the <strong>Custom CSS</strong> section, apply the font at a root level. For example:</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
    <span class="hljs-attribute">--a-base-font-family</span>: <span class="hljs-string">"Nunito"</span>, sans-serif;
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">18px</span>; // Optional. <span class="hljs-attribute">Default</span>: <span class="hljs-number">16px</span>.
}
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">🎗</div>
<div data-node-type="callout-text">Note that the font family name can be found on the <strong><em>Get Embed Code </em></strong>page in Google Fonts.</div>
</div>

<p>A couple of things to highlight from the example:</p>
<ul>
<li><p>The <code>font-family</code> attribute is set at the top of the hierarchy using the <code>:root</code> pseudo-class. Learn more about it <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/:root">here</a>.</p>
</li>
<li><p>To set the font, override the CSS variable <code>--a-base-font-family</code> instead of setting the attribute directly. Learn more about it <a target="_blank" href="https://apex.oracle.com/pls/apex/r/apex_pm/ut/css-variables">here</a>.</p>
</li>
<li><p>Optionally, you can globally change the font size by simply setting the base font size at the root level as well.</p>
</li>
</ul>
<h2 id="heading-micromanaging-font-sizes">Micromanaging font sizes</h2>
<p>If you need precise control over the font sizes of specific components, the Universal Theme in Oracle APEX offers the tools to do so sustainably. The recommended approach is to override the specific CSS variable for your case.</p>
<p>For setting up font sizes, the Universal Theme uses <code>rem</code> as a unit, making all font sizes relative to the root font size. Learn more about it <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">here</a>.</p>
<p>For example, if you set the font size to <code>18px</code> at the <code>:root</code> level, it will affect all relative sizes across your application, ensuring consistency.</p>
<p>An example of micromanaging font sizes might involve overriding specific components at the top level, as illustrated below:</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
    <span class="hljs-attribute">--a-button-font-size</span>: <span class="hljs-number">0.75rem</span>;    
    <span class="hljs-attribute">--a-checkbox-label-font-size</span>: <span class="hljs-number">0.75rem</span>;
    <span class="hljs-attribute">--a-checkbox-label-font-size</span>: <span class="hljs-number">0.875rem</span>;
    <span class="hljs-attribute">--a-checkbox-label-font-size</span>: <span class="hljs-number">1rem</span>;
    <span class="hljs-attribute">--a-chip-font-size</span>: <span class="hljs-number">0.75rem</span>;
    <span class="hljs-attribute">--a-chip-input-font-size</span>: <span class="hljs-number">0.75rem</span>;
    <span class="hljs-attribute">--a-cv-badge-font-size</span>: <span class="hljs-number">0.75rem</span>;
}
</code></pre>
<p>If you want to learn more about CSS variables, you can find the full list of them <a target="_blank" href="https://apex.oracle.com/i/themes/theme_42/23.2/docs/Core.html#ut-base-font-size">here</a>.</p>
<h2 id="heading-identifying-the-correct-css-variable">Identifying the Correct CSS Variable</h2>
<p>Determining the right CSS class that needs to be overwritten can sometimes be challenging. In this case, you can simply use your browser's web development tools to inspect the rendered code and identify the variable being used.</p>
<p>Here’s an example: Imagine you want to increase the font size of card titles globally. To do this, inspect the card title in your browser by right-clicking on the title — in this case, <strong>KING.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723019792869/4e4ea406-0e8b-46de-8a54-ed1a1a8f2236.png" alt="Oracle APEX - Inspect the Card Title Element" class="image--center mx-auto" /></p>
<p>In the Inspector section (this example is from Firefox, but it should be similar in other browsers), you should see something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723019961636/49f03fcc-f5ad-49bc-ae3a-7f5c2c7b9258.png" alt="Web development Tools, Code Inspector in Firefox" class="image--center mx-auto" /></p>
<p>As you can see, the CSS properties of the <code>a-CardView-title</code> class are as follows:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.a-CardView-title</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--a-cv-title-text-color);
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--a-cv-title-font-size,<span class="hljs-number">16px</span>);
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-built_in">var</span>(--a-cv-title-font-weight,<span class="hljs-number">700</span>);
  <span class="hljs-attribute">line-height</span>: <span class="hljs-built_in">var</span>(--a-cv-title-line-height,<span class="hljs-number">20px</span>);
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
}
</code></pre>
<p>In this example, we're interested in the font size, so the <code>--a-cv-title-font-size</code> variable is the one we need. You can overwrite this at any level, depending on your needs. As mentioned earlier, you can do this at the root level:</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
   <span class="hljs-attribute">--a-cv-title-font-size</span>: <span class="hljs-number">1.5rem</span>;
}
</code></pre>
<p>And here is the final result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723020462320/41d8b9c8-da5c-4e0e-8ee2-e20b91ea8966.png" alt class="image--center mx-auto" /></p>
<p>Enjoy Life!</p>
]]></content:encoded></item></channel></rss>