<?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[Petar Simic, Oracle Blog]]></title><description><![CDATA[Oracle APEX Consultant]]></description><link>https://petarsimic.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 02 Sep 2026 09:25:22 GMT</lastBuildDate><atom:link href="https://petarsimic.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Oracle APEX: How to Translate Internal Messages]]></title><description><![CDATA[Ever needed to change a default button label like "Show All", "Cancel" or "No Results found" in Oracle APEX? Whether you're building an application in a single language that isn't English or managing ]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-how-to-translate-internal-messages</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-how-to-translate-internal-messages</guid><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Sun, 31 May 2026 11:44:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/p5VW_ZUon7o/upload/fbd921fc82f7acbbb6dc774e45b68b17.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ever needed to change a default button label like "Show All", "Cancel" or "No Results found" in Oracle APEX? Whether you're building an application in a single language that isn't English or managing a complex multilingual system, customizing the default UI text is a fundamental requirement. Instead of searching for complex workarounds, you can use APEX's powerful and straightforward globalization features. This built-in toolset is the key to creating a fully localized and professional user experience. For example - Show All in Region Display Selector:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770195123209/913c3407-a050-4a07-8d85-58c3f9f38ebb.png" alt="" style="display:block;margin:0 auto" />

<h2>Translating “Show All” Message</h2>
<p>To translate the text to Serbian and replace "Show All" with "Prikazi sve" in Oracle APEX, you can use the platform's feature for modifying internal text messages. Navigate to <strong>Shared Components / Globalization / Text Messages</strong> in APEX, and create a new text message. For the "Show All" message, use the message name <code>SHOW_ALL</code> and set the text to "Prikazi sve" This will automatically update the message in your APEX application.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770195333611/d982adb8-b623-4438-a739-13bb8d4bf45c.png" alt="" style="display:block;margin:0 auto" />

<p>As I mentioned earlier, we will use the SHOW_ALL message name for this purpose. However, if our applications are adjusted accordingly, you should also configure the language settings to match the desired language for your users. By doing so, you ensure that the "Show All" text is displayed correctly in the user's preferred language. Below is the screenshot of the Create/Edit Text Message form.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770195753938/6358f399-cdba-4e0f-83bb-1faf5e7902d6.png" alt="" style="display:block;margin:0 auto" />

<p>Now, we have successfully configured our APEX application to automatically translate the "Show All" message as you can see on the screenshot below.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770195797529/00a278ff-3ebf-43a0-aafa-48d83b7cecfe.png" alt="" style="display:block;margin:0 auto" />

<p>Full list of available text messages -</p>
<h2>Conclusion</h2>
<p>So, the next time you see a default English label that doesn't fit your application, you know exactly what to do. The power to fully localize your APEX application is just a few clicks away in the Text Messages settings. Use it to take your user experience to the next level.</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX: Comparing APEX Apps and Pages Across Environments]]></title><description><![CDATA[Introduction
I recently remembered this functionality and wanted to share it with you. If you need to ensure that your APEX application or a specific page remains consistent across various environment]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-comparing-apex-apps-and-pages-across-environments</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-comparing-apex-apps-and-pages-across-environments</guid><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Sun, 10 May 2026 17:30:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/650d9009b8736841c0da7ea4/840dd2c8-dd84-45ac-b1ce-5cea78b57760.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>Introduction</h3>
<p>I recently remembered this functionality and wanted to share it with you. If you need to ensure that your APEX application or a specific page remains consistent across various environments, APEX offers a built-in feature designed for this task.</p>
<h3>Getting Page level Checksum</h3>
<p>When you want to compare specific Oracle APEX page, just do the following.</p>
<ol>
<li><p>In the App Designer, choose the application with the page you want to compare.</p>
</li>
<li><p>Click on the page you want to compare.</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/650d9009b8736841c0da7ea4/a3d0ae0a-784e-4767-aeac-65bc8301f1de.png" alt="" style="display:block;margin:0 auto" />

<ol>
<li>Click on the tool icon then Checksum.</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/650d9009b8736841c0da7ea4/1c04bac0-a2aa-464e-acf7-339197f50cab.png" alt="" style="display:block;margin:0 auto" />

<p>Then you will see the page checksum.</p>
<img src="https://cdn.hashnode.com/uploads/covers/650d9009b8736841c0da7ea4/4e00142f-040f-4d77-bcac-1595b2e242ad.png" alt="" style="display:block;margin:0 auto" />

<p>Now, you can do the same in target environment and compare if checksum is the same.</p>
<h3>Getting Application Level Checksum</h3>
<ol>
<li><p>In the App Builder choose the application you want to get checksum for.</p>
</li>
<li><p>In the App Builder home page go to Utilities.</p>
</li>
<li><p>Click Application Checksum</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/650d9009b8736841c0da7ea4/f8f3cb6a-b9fe-4ca6-99c4-1c1f11d5f782.png" alt="" style="display:block;margin:0 auto" />

<p>Now, you can compare the hash and also see the number of pages, regions, and items in the app.</p>
<h3>Conclusion</h3>
<p>APEX Checksum utility is a hidden gem for maintaining environment parity. Whether you are troubleshooting a bug that only appears on one instance or verifying a deployment to multiple production workspaces</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX: How to Publish APEX (PWA) to the Apple App Store]]></title><description><![CDATA[Following the publication of the blog on "How to Publish APEX (PWA) to the Google Play Store", the next topic is publishing the APEX PWA app to the Apple App Store.
Prerequisites
Before you start, ens]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-how-to-publish-apex-pwa-to-the-apple-app-store</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-how-to-publish-apex-pwa-to-the-apple-app-store</guid><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Tue, 07 Apr 2026 07:51:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/9e9PD9blAto/upload/3f588ff003830ab09dcbb9720710dac9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Following the publication of the blog on "<a href="https://petarsimic.hashnode.dev/oracle-apex-how-to-publish-apex-pwa-to-the-google-play-store">How to Publish APEX (PWA) to the Google Play Store</a>", the next topic is publishing the APEX PWA app to the Apple App Store.</p>
<h2>Prerequisites</h2>
<p>Before you start, ensure you have the following:</p>
<ol>
<li><p><strong>A Valid PWA</strong>: Your app must be a PWA with a web manifest and be accessible via HTTPS.</p>
</li>
<li><p><strong>Apple Developer Account</strong>: Sign up for an Apple developer account, which costs $100 annually.</p>
</li>
<li><p><strong>UI/UX</strong>: Have a nice UI and UX in the app, otherwise app will be rejected.</p>
</li>
<li><p><strong>Follow Developer Content Policy</strong>: it is required to follow the polices from the following link <a href="https://developer.apple.com/app-store/app-privacy-details/">https://developer.apple.com/app-store/app-privacy-details/</a></p>
</li>
<li><p><strong>XCode and Simulator</strong>: You will need XCode and Simulator to build and test your app.</p>
</li>
<li><p><strong>Patience</strong>: before published - app might be rejected a few times by Apple, asking for some changes in your app.</p>
</li>
</ol>
<h2>Web App Manifest</h2>
<p>The first thing to start with is the Web Manifest, where you can configure key details of your PWA app.</p>
<p>A web manifest is a JSON (JavaScript Object Notation) file that provides important configuration settings for a Progressive Web App (PWA). It plays a crucial role in defining how your web application should behave when installed on a user's device.</p>
<p>The manifest is crucial because it bridges the gap between a web app and a native app. By defining these settings, you ensure that your PWA behaves like a native app when installed, providing a seamless and engaging user experience. This consistency is key to user adoption and satisfaction.</p>
<p>Here are the key elements and their importance:</p>
<ol>
<li><p><strong>name</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: This is the full name of your web application.</p>
</li>
<li><p><strong>Importance</strong>: It is displayed to the user in various contexts, such as the app's title on the home screen and in the app launcher.</p>
</li>
</ul>
</li>
<li><p><strong>short_name</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: A shorter version of the app's name.</p>
</li>
<li><p><strong>Importance</strong>: Used where space is limited, such as on the device's home screen.</p>
</li>
</ul>
</li>
<li><p><strong>icons</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: An array of images representing different icon sizes for your app.</p>
</li>
<li><p><strong>Importance</strong>: Essential for providing a recognizable and professional appearance on different devices and screen resolutions. Recommended sizes include 192x192, 384x384, and 1024x1024 pixels.</p>
</li>
</ul>
</li>
<li><p><strong>theme_color</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: The color of the browser's UI elements when the app is launched.</p>
</li>
<li><p><strong>Importance</strong>: Enhances the user's experience by providing a consistent color theme.</p>
</li>
</ul>
</li>
<li><p><strong>background_color</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: The background color of the splash screen displayed when the app is launched.</p>
</li>
<li><p><strong>Importance</strong>: Improves the visual transition from the splash screen to the app.</p>
</li>
</ul>
</li>
<li><p><strong>display</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: Defines how the app should be displayed when launched.</p>
</li>
<li><p><strong>Options</strong>:</p>
<ul>
<li><p><strong>fullscreen</strong>: Suitable for games or apps that require maximum screen space.</p>
</li>
<li><p><strong>standalone</strong>: The most common setting, hides the URL bar, making the app look like a native app.</p>
</li>
</ul>
</li>
<li><p><strong>Importance</strong>: Determines the user interface and experience of the app.</p>
</li>
</ul>
</li>
<li><p><strong>start_url</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: The URL where the app should start when launched.</p>
</li>
<li><p><strong>Importance</strong>: Ensures that the app opens at the correct entry point.</p>
</li>
</ul>
</li>
<li><p><strong>orientation</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: Specifies the default orientation (portrait or landscape) for the app.</p>
</li>
<li><p><strong>Importance</strong>: Helps provide the best user experience by locking the app to the preferred orientation.</p>
</li>
</ul>
</li>
<li><p><strong>scope</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: Defines the navigation scope of the app, restricting which URLs the app can navigate to.</p>
</li>
<li><p><strong>Importance</strong>: Ensures that navigation stays within the app context.</p>
</li>
</ul>
</li>
<li><p><strong>description</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: A brief description of the web application.</p>
</li>
<li><p><strong>Importance</strong>: Provides users with an understanding of what the app does.</p>
</li>
</ul>
</li>
</ol>
<h3>Example of a Web Manifest</h3>
<pre><code class="language-json">{
  "name": "myapp.com",
  "short_name": "MyApp",
  "icons": [
    {
      "src": "icon-48x48.png",
      "sizes": "48x48",
      "type": "image/png"
    },
    {
      "src": "icon-48x48.png",
      "sizes": "72x72",
      "type": "image/png"
    },
    ...
  ],
  "theme_color": "#007bff",
  "background_color": "#ffffff",
  "display": "standalone",
  "start_url": "/",
  "orientation": "portrait",
  "scope": "/",
  "description": "Description of the app"
}
</code></pre>
<p>More about app Manifest - <a href="https://www.w3.org/TR/appmanifest/">https://www.w3.org/TR/appmanifest/</a></p>
<p>In APEX, you can add it by navigating to <strong>Shared Components &gt; Progressive Web App &gt; Custom Manifest</strong>.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719751277098/26118541-3b4a-4c29-87b3-7d611fa0d399.png?auto=compress,format&amp;format=webp" alt="Custom Manifest in Oracle APEX" />

<h2>Packaging Your PWA App</h2>
<p>To package the PWA into an iOS app, I will utilize PWABuilder, which streamlines the process. Follow these steps to package the APEX app using PWABuilder.</p>
<h3>PWABuilder</h3>
<p>This powerful tool is designed to simplify the process of converting Progressive Web Apps (PWAs) into platform-specific apps, such as those for Android, iOS, Microsoft and Meta Quest. Created by Microsoft, PWABuilder offers an intuitive and straightforward way for developers to package their web applications and make them available across various app stores, enhancing the app's accessibility and user reach.</p>
<ol>
<li><p><strong>Visit PWABuilder</strong>: Go to <a href="https://www.pwabuilder.com">PWABuilder.com</a>.</p>
</li>
<li><p><strong>Enter Your PWA URL</strong>: Input the URL of your PWA and click Start button.</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719913990800/df53fb35-45ec-41ac-9835-17941ae225d5.png?auto=compress,format&amp;format=webp" alt="PWABuilder Home Page" />

<ol>
<li><strong>Select Packaging Option</strong>: Click "Package for stores".</li>
</ol>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719914111191/2434dbcb-b41c-4ff2-9c16-8594cfc019c8.png?auto=compress,format&amp;format=webp" alt="PWABuilder - Package For Stores" />

<ol>
<li><strong>Generate Apple Package</strong>: Choose "Generate Package" under the iOS section.</li>
</ol>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743613698525/a192ab2c-09d0-4865-8c22-6852cb858b91.png" alt="" style="display:block;margin:0 auto" />

<h3><strong>Building Your App</strong></h3>
<p>Next, build the Xcode project that integrates your PWA:</p>
<ol>
<li><p>Unzip the downloaded folder from PWABuilder.</p>
</li>
<li><p>Open a terminal and navigate to the "src" directory.</p>
</li>
<li><p>Run pod install. Note: If facing an error, like - <code>zsh: command not found: pod</code></p>
</li>
</ol>
<p>Run the following command –</p>
<pre><code class="language-bash">sudo gem install -n /usr/local/bin cocoapods
</code></pre>
<p>run the pod install again, the command should execute without an error this time.</p>
<pre><code class="language-bash">pod install
</code></pre>
<ol>
<li><p>Open the .xcworkspace file in your "src" directory. (Do not open the .xcodeproj file.)</p>
</li>
<li><p>Click "Product" &gt; "Build" in Xcode to compile your project.</p>
</li>
</ol>
<p>Don’t select anything from left navigation or anywhere.</p>
<ol>
<li>Test your PWA on an iPhone simulator by clicking the Product &gt; Run it might ask you to install the Simulator.</li>
</ol>
<h3><strong>Capabilities</strong></h3>
<p>Under the Xcode Signing &amp; Capabilities tab, disable any unnecessary capabilities to ensure successful publishing verification. Leave Audio, AirPlay and picture in picture, Background processing and Remote Notifications.</p>
<p>All the icons and Screenshots need to be adjusted to not use the Alpha channel. (transparency).</p>
<p>On the Mac open the icon in Preview app &gt; File &gt; Export &gt; uncheck the Alpha and save.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743614570081/cfa079ca-1f10-4268-a670-f2b20836ab88.png" alt="" style="display:block;margin:0 auto" />

<h3>Publishing Process</h3>
<ol>
<li><p><strong>Sign Into Your Apple Developer Account</strong>: Log in to your Apple Developer Account. - <a href="https://appstoreconnect.apple.com/login">https://appstoreconnect.apple.com/login</a></p>
</li>
<li><p><strong>Create a Bundle ID</strong>:</p>
<ul>
<li><p>Navigate to your Apple Developer account page and select Certificates, Identifiers &amp; Profiles.</p>
</li>
<li><p>Click on Identifiers and then the '+' symbol to add a new identifier.</p>
</li>
<li><p>Choose App as the type.</p>
</li>
<li><p>Provide a Description and your Bundle ID, ensuring it matches the one from PWABuilder.</p>
</li>
<li><p>Enable Associated Domains and Push Notifications in the capabilities section.</p>
</li>
<li><p>Click Continue and then Register to complete the process.</p>
</li>
</ul>
</li>
<li><p><strong>Create a Certificate Signing Request (CSR)</strong></p>
</li>
</ol>
<p>To proceed with the app deployment process, you need to generate a Certificate Signing Request (CSR) using the Keychain Access application. Follow these steps:</p>
<ol>
<li><p><strong>Launch Keychain Access</strong>: Open the Keychain Access app on your system. (MacOS)</p>
</li>
<li><p><strong>Access Certificate Assistant</strong>: From the top menu bar, navigate to Keychain Access &gt; Certificate Assistant &gt; Request a Certificate from a Certificate Authority.</p>
</li>
<li><p><strong>Enter Details</strong>: Input your email address and name. The CA Email Address can be left empty.</p>
</li>
<li><p><strong>Save the Request</strong>: Choose the option to save to disk and proceed.</p>
</li>
</ol>
<p><strong>Step 4: Create a Certificate</strong></p>
<p>With the CSR generated in the previous step, you'll now create a certificate.</p>
<ol>
<li><p><strong>Access Apple Developer Account</strong>: Return to the Certificates, Identifiers, &amp; Profiles section on your Apple Developer account.</p>
</li>
<li><p><strong>Add Certificate</strong>: Select Certificates and use the '+' symbol to add a new certificate.</p>
</li>
<li><p><strong>Select Type</strong>: Choose Apple Distribution and continue.</p>
</li>
<li><p><strong>Upload CSR</strong>: Upload the Certificate Signing Request file previously created.</p>
</li>
<li><p><strong>Download Certificate</strong>: After verification, download the .cer file to your disk.</p>
</li>
</ol>
<p><strong>Step 5: Install the Certificate</strong></p>
<p>Now, install the downloaded certificate by following these steps:</p>
<ol>
<li><p><strong>Open Keychain Access</strong>: Launch the Keychain Access app.</p>
</li>
<li><p><strong>Navigate</strong>: Ensure you're in the login section on the left sidebar.</p>
</li>
</ol>
<p><strong>Install</strong>: In the last step just drag the downloaded certificate to the list of certificates in the <strong>Keychain Access</strong> app.</p>
<p><strong>Step 6: Create a Provisioning Profile</strong></p>
<p>Using the created certificate, generate a Provisioning Profile as follows:</p>
<ol>
<li><p><strong>Access Developer Account</strong>: Return to the Certificates, Identifiers, &amp; Profiles section.</p>
</li>
<li><p><strong>Create Profile</strong>: Select Profiles and add a new profile.</p>
</li>
<li><p><strong>Select Type</strong>: Choose App Store under Distribution.</p>
</li>
<li><p><strong>Configure</strong>: Select the appropriate App ID and certificate.</p>
</li>
<li><p><strong>Generate Profile</strong>: Provide a name for the Provisioning Profile and generate it.</p>
</li>
<li><p><strong>Download Profile</strong>: download the .mobileprovision file.</p>
</li>
</ol>
<p><strong>Step 7: Create Your App Reservation</strong></p>
<p>Now, reserve your app in the App Store Connect:</p>
<ol>
<li><p><strong>Access App Store Connect</strong>: Return to your Apple Developer account and navigate to App Store Connect.</p>
</li>
<li><p><strong>Create App</strong>: Select My Apps and click on the '+' symbol to add a new app.</p>
</li>
<li><p><strong>Provide Details</strong>: Fill in the required details including platform, app name, language, Bundle ID, SKU (can be any number), and user access.</p>
</li>
<li><p><strong>Complete Reservation</strong>: Click Create to finalize the app reservation.</p>
</li>
</ol>
<p><strong>Step 8: Upload Your App Package</strong></p>
<p>Upload app package to the App Store Connect:</p>
<p>1. Under Xcode &gt; Preferences &gt; Account add your Apple Developer Account</p>
<p>2. Go to your project in the left menu &gt; Build Settings &gt; Under signing set Code Signing Style Release to Manual &gt; under Development Team set Release to your Account &gt; under Provisioning Profile &gt; select Download profile (choose the profile you created). At the top of the Xcode.</p>
<p>The image below shows how to select the project.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745070887164/4a7fa66d-66b9-46ed-8626-3b3cad374b2c.png" alt="" style="display:block;margin:0 auto" />

<p><strong>Step 9: Submit for Review</strong></p>
<p>Submit your app for review to initiate the approval process:</p>
<ol>
<li><p><strong>Access App List</strong>: Navigate to your apps list in App Store Connect.</p>
</li>
<li><p><strong>Select Build</strong>: Choose the build you just uploaded.</p>
</li>
<li><p><strong>Submit</strong>: Hit Submit for Review to complete the submission.</p>
</li>
</ol>
<h2>Conclusion</h2>
<p>Publishing your Oracle APEX PWA to the Apple App Store is definitely achievable — and using PWA Builder can make the native packaging step much smoother. PWA Builder helps you generate an iOS wrapper so you can focus on polishing the web app while handling much of the bridging work required for App Store submission.</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX: Faceted Search - External Page Item]]></title><description><![CDATA[When working with Faceted Search in Oracle APEX, you might want more control over where certain search elements appear. For example, instead of being stuck in the default search area, you might prefer to place them in more user-friendly locations. Lu...]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-faceted-search-external-page-item</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-faceted-search-external-page-item</guid><category><![CDATA[orclapex]]></category><category><![CDATA[Apex]]></category><category><![CDATA[#oracle-apex]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Tue, 23 Sep 2025 10:47:17 GMT</pubDate><content:encoded><![CDATA[<p>When working with Faceted Search in Oracle APEX, you might want more control over where certain search elements appear. For example, instead of being stuck in the default search area, you might prefer to place them in more user-friendly locations. Luckily, APEX provides a built-in way to do this.</p>
<p>By default, all facets are positioned in the Faceted Search area, as shown in the image below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758188697497/1247b85c-adef-4b3b-9080-2340369c6f52.png" alt class="image--center mx-auto" /></p>
<p>First, we need to create a page item and give it a name, then position it on the page.</p>
<p>Let’s say I want to move the search field below the Breadcrumb and keep it synchronized with other facets and charts. In that case, I should use the External Page Item option of Input Field attribute of that search facet.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758193296267/894434f1-aa7e-4d81-a97a-c8257c5a99de.png" alt class="image--center mx-auto" /></p>
<p>We reference our page item in the Input Field attribute.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758193566917/f717df1f-352e-456b-9a2f-90ee966db941.png" alt class="image--center mx-auto" /></p>
<p>With these steps completed, your external page item is now fully set up and ready to function as a search field. This means that the search field, which you have created outside the default Faceted Search area, will now operate seamlessly in its new location.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Note: Once you specify your External Page Item, the search facet will disappear, and all its functionality will be transferred to your page item.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1758623914442/8bcb4083-0ca9-411d-8ebe-c0cf5d114005.png" alt class="image--center mx-auto" /></p>
<p>I hope you find this post helpful and informative. By following the steps outlined above, you can effectively move facets outside the default Faceted Search area, allowing for greater flexibility in your application's design. This can enhance the user experience by positioning search fields and other elements in more intuitive or accessible locations.</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX: Tree Region Expand Selected Node Only]]></title><description><![CDATA[Recently I was working with Tree region and some requests that are not declaratively available in APEX. So I discovered some useful APIs that I think is worth sharing. :)
Expand Selected Node
In APEX, we have Dynamic Actions to expand all and collaps...]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-tree-region-expand-selected-node-only</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-tree-region-expand-selected-node-only</guid><category><![CDATA[#oracle-apex]]></category><category><![CDATA[Oracle]]></category><category><![CDATA[orclapex]]></category><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Sat, 15 Mar 2025 13:40:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741959943617/b417804e-fb04-4df0-8f10-e70643355b99.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently I was working with Tree region and some requests that are not declaratively available in APEX. So I discovered some useful APIs that I think is worth sharing. :)</p>
<h2 id="heading-expand-selected-node">Expand Selected Node</h2>
<p>In APEX, we have Dynamic Actions to expand all and collapse all nodes. However, if we want to expand only a selected node, we need help from JavaScript APIs.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> tree$ = $( <span class="hljs-string">"#projTrackTree"</span> );
tree$.treeView( <span class="hljs-string">"expand"</span>, tree$.treeView( <span class="hljs-string">"getSelection"</span> ) );
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Note that #projTrackTree is Static Id of the Tree region.</div>
</div>

<p>If you want to collapse all nodes and expand only the selected one, use the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> tree$ = $( <span class="hljs-string">"#projTrackTree"</span> );
tree$.treeView(<span class="hljs-string">"collapseAll"</span>);
tree$.treeView( <span class="hljs-string">"expand"</span>, tree$.treeView( <span class="hljs-string">"getSelection"</span> ) );
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741949083595/3a3e2d6a-ef9e-484a-bc64-de719a16f764.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-expand-selected-node-on-page-reload">Expand Selected Node on Page Reload</h2>
<p>If you reload or submit the page when a node is clicked, the selected node will not remain active by default.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742042746129/2be4b912-7781-4bd3-8613-615f05b71c8e.gif" alt class="image--center mx-auto" /></p>
<p>To achieve this, we can use the <strong>Selected Node Page Item</strong> attribute.</p>
<h3 id="heading-selected-node-page-item">Selected Node Page Item</h3>
<p>This option is declaratively available in Oracle APEX. When the page is reloaded, the item's value is used to select the active node. You can find this option under <strong>Tree Region &gt; Attributes &gt; Selected Node Page Item</strong>, as shown in the screenshot below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741894187429/f8869755-a8ba-4ed0-a349-024f9fb00cb6.png" alt class="image--center mx-auto" /></p>
<p>The page item should be set either via the node link or a page process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742042956773/c5d7320c-6db1-4245-9f63-a6f9e0c81eed.gif" alt class="image--center mx-auto" /></p>
<p>If you want to expand the selected node after a page reload, you can use the previous JavaScript snippet on page load.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742043314719/5684a54a-ce9a-48de-8185-adedf661a156.png" alt class="image--center mx-auto" /></p>
<p>Result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742043437855/389c62ef-130c-48c8-8dc5-9fe1b3f3e8d5.gif" alt class="image--center mx-auto" /></p>
<p>With these techniques, you can easily control node expansion and improve the user experience in your APEX application.</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX: Working with Row Selection in Interactive Grid]]></title><description><![CDATA[The Interactive Grid (IG) in Oracle APEX provides a feature to select rows when edit mode is enabled. However, it comes with challenges such as:

Retrieving all selected records

Maintaining selected records between pagination pages

Preselecting spe...]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-working-with-row-selection-in-interactive-grid</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-working-with-row-selection-in-interactive-grid</guid><category><![CDATA[#oracle-apex]]></category><category><![CDATA[interactive-grid]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Fri, 14 Feb 2025 13:10:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739537902649/d57aeaa9-3632-42b7-b6d9-7b0800189ce9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The <strong>Interactive Grid (IG)</strong> in Oracle APEX provides a feature to select rows when edit mode is enabled. However, it comes with challenges such as:</p>
<ul>
<li><p>Retrieving all selected records</p>
</li>
<li><p>Maintaining selected records between pagination pages</p>
</li>
<li><p>Preselecting specific records</p>
</li>
</ul>
<h2 id="heading-getting-selected-records">Getting Selected Records</h2>
<p>Starting from <strong>APEX 24.1</strong>, a new <strong>JavaScript API</strong> called <code>selectionStateItem</code> allows setting an APEX page item with the selected values whenever the selection changes. More details are available in the <a target="_blank" href="https://apex.oracle.com">APEX documentation</a>.</p>
<h4 id="heading-implementation">Implementation</h4>
<p>Add the following code to: <strong>IG &gt; Attributes &gt; Advanced &gt; Initialization JavaScript Function</strong></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">options</span>) </span>{
    options.defaultGridViewOptions = {
        <span class="hljs-attr">selectionStateItem</span>: <span class="hljs-string">"P100_SELECTED_IDS"</span>
    }

    <span class="hljs-keyword">return</span> options;
}
</code></pre>
<p><strong>Result</strong>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739455473965/d3b69b7e-eafc-411f-a451-2aac514e030b.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-persisting-selection-between-pages">Persisting Selection Between Pages</h2>
<p>By default, when pagination is set to <strong>"Page"</strong>, selected records are lost when navigating between pages.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739456020126/5afcabda-9c55-4cbc-b6bf-dd59e38009e4.gif" alt class="image--center mx-auto" /></p>
<p>To retain selection, use the <strong>APEX JS API</strong> <code>persistSelection</code>, which ensures records remain selected across pagination pages.</p>
<h4 id="heading-implementation-1">Implementation</h4>
<p>Add the following code to: <strong>IG &gt; Attributes &gt; Advanced &gt; Initialization JavaScript Function</strong></p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">options</span>) </span>{
    options.defaultGridViewOptions = {
        <span class="hljs-attr">rowsPerPage</span>: <span class="hljs-number">5</span>,
        <span class="hljs-attr">persistSelection</span>: <span class="hljs-literal">true</span>
    }

    <span class="hljs-keyword">return</span> options;
}
</code></pre>
<p>Result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739526334751/826f5ea0-4af1-4922-b8bd-95889b1725f6.gif" alt class="image--center mx-auto" /></p>
<h3 id="heading-preselect-records">Preselect Records</h3>
<p>If you need to retain selected records after a page refresh or preselect specific rows when the page loads, you can achieve this using JavaScript.</p>
<p>Implementation Add the following code to: <strong>Execute when Page Loads</strong> or <strong>a</strong> <strong>Dynamic Action on Page Load</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> val = $v(<span class="hljs-string">"P100_SAVED_IDS"</span>);
<span class="hljs-keyword">if</span> (val) {
    <span class="hljs-keyword">var</span> array = val.split(<span class="hljs-string">":"</span>).filter(<span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> id.trim() !== <span class="hljs-string">""</span>); <span class="hljs-comment">// Remove empty values</span>
    <span class="hljs-keyword">if</span> (array.length &gt; <span class="hljs-number">0</span>) {
        apex.region(<span class="hljs-string">'IG_DEMO'</span>).widget().interactiveGrid(<span class="hljs-string">'setSelectedRecords'</span>, array);
    }
}
</code></pre>
<p>This approach ensures that <strong>selected records persist</strong>, improving user experience when working with <strong>Interactive Grid selections</strong> in Oracle APEX.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By leveraging the <strong>selectionStateItem</strong>, <strong>persistSelection</strong>, and <strong>setSelectedRecords</strong> APIs in APEX Interactive Grid, you can efficiently manage row selection, ensuring a smoother user experience.</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX: Auditing User-Requested Data]]></title><description><![CDATA[Recently, I was asked how to track the data displayed to users on Reports and Forms in Oracle APEX. The requirement was to prevent displaying any data before search/filter criteria are entered, and to limit the number of rows shown. After some resear...]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-audit-data-displayed-to-the-users</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-audit-data-displayed-to-the-users</guid><category><![CDATA[#oracle-apex]]></category><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Tue, 11 Feb 2025 08:49:36 GMT</pubDate><content:encoded><![CDATA[<p>Recently, I was asked how to track the data displayed to users on Reports and Forms in Oracle APEX. The requirement was to prevent displaying any data before search/filter criteria are entered, and to limit the number of rows shown. After some research, I discovered that combining APEX views with the <strong>apex_region.open_query_context</strong> built-in function can be a powerful solution to address this challenge.</p>
<p>This post will focus specifically on retrieving Report and Form data shown to the user.</p>
<h2 id="heading-understanding-the-apexregionopenquerycontext-function">Understanding the <code>apex_region.open_query_context</code> Function</h2>
<p>The <code>apex_region.open_query_context</code> function returns APEX_EXEC query context returning current region data. Only native region types are supported. More about function <a target="_blank" href="https://docs.oracle.com/en/database/oracle/apex/24.1/aeapi/APEX_REGION-OPEN_QUERY_CONTEXT-Function.html">here</a>.</p>
<p>Here’s an example of how to use it:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DECLARE</span>
       l_context apex_exec.t_context;
<span class="hljs-keyword">BEGIN</span>
       l_context := apex_region.open_query_context (
              p_page_id =&gt; <span class="hljs-number">1</span>,
              p_region_id =&gt; <span class="hljs-number">2505704029884282</span> );

       while apex_exec.next_row(l_context)
       loop

          sys.dbms_output.put_line(
            'ENAME: ' || apex_exec.get_varchar2( p_context =&gt; l_context, p_column_name =&gt; 'ENAME') ||
            'MGR: ' || apex_exec.get_varchar2( p_context =&gt; l_context, p_column_name =&gt; 'MGR') ||
            'SAL: ' || apex_exec.get_varchar2( p_context =&gt; l_context, p_column_name =&gt; 'SAL') 
          );

       <span class="hljs-keyword">end</span> <span class="hljs-keyword">loop</span>;
       apex_exec.close(l_context);
<span class="hljs-keyword">END</span>;
</code></pre>
<p>Or an example to how to get it in the JSON format:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">DECLARE</span>
       l_context apex_exec.t_context;
<span class="hljs-keyword">BEGIN</span>
       l_context := apex_region.open_query_context (
              p_page_id =&gt; <span class="hljs-number">1</span>,
              p_region_id =&gt; <span class="hljs-number">2505704029884282</span>);

       apex_json.open_object;
       apex_json.write_context( 'data', l_context );
       apex_json.close_object;
<span class="hljs-keyword">END</span>;
</code></pre>
<p>As you can see in the code above, function is called with two parameters:</p>
<ul>
<li><p><code>p_page_id</code>, which represents the ID of the page where the report is located.</p>
</li>
<li><p><code>p_region_id</code>, which is the internal ID of the report.</p>
</li>
</ul>
<p>To avoid hardcoding the <code>region_id</code>, a simple query to the APEX view will provide that information.</p>
<h3 id="heading-retrieving-the-regionid-from-apex-views">Retrieving the <code>region_id</code> from APEX views</h3>
<p>Before executing the query, it’s essential to set a Static ID for the report region.</p>
<p>Once you’ve set the Static ID, you can write a query to retrieve the <code>region_id</code> from the <code>apex_application_page_regions</code> APEX view:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736729423682/e5046edf-6e09-40ec-8904-2ec2f256be32.png" alt="Oracle APEX - Static ID" class="image--center mx-auto" /></p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> region_id
<span class="hljs-keyword">from</span> apex_application_page_regions
<span class="hljs-keyword">where</span> <span class="hljs-number">1</span> = <span class="hljs-number">1</span>
  <span class="hljs-keyword">and</span> application_id = :APP_ID
  <span class="hljs-keyword">and</span> page_id = :APP_PAGE_ID
  <span class="hljs-keyword">and</span> static_id = <span class="hljs-string">'EMP_RPT'</span>;
</code></pre>
<h3 id="heading-example-output-of-the-apexregionopenquerycontext-function">Example Output of the <code>apex_region.open_query_context</code> Function</h3>
<p>Assume you have a report that displays 3 rows of data.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736730871465/9ee1d8b9-a644-4ff6-9983-f760b1898bd7.png" alt class="image--center mx-auto" /></p>
<p>Below is an example of the JSON output from the <code>apex_region.open_query_context</code> function:</p>
<pre><code class="lang-json">{
   <span class="hljs-attr">"data"</span>:[
      {
         <span class="hljs-attr">"EMPNO"</span>:<span class="hljs-number">7698</span>,
         <span class="hljs-attr">"ENAME"</span>:<span class="hljs-string">"BLAKE"</span>,
         <span class="hljs-attr">"JOB"</span>:<span class="hljs-string">"MANAGER"</span>,
         <span class="hljs-attr">"MGR"</span>:<span class="hljs-number">7839</span>,
         <span class="hljs-attr">"HIREDATE"</span>:<span class="hljs-string">"1981-05-01T00:00:00Z"</span>,
         <span class="hljs-attr">"SAL"</span>:<span class="hljs-number">2850</span>,
         <span class="hljs-attr">"DEPTNO"</span>:<span class="hljs-number">30</span>
      },
      {
         <span class="hljs-attr">"EMPNO"</span>:<span class="hljs-number">7782</span>,
         <span class="hljs-attr">"ENAME"</span>:<span class="hljs-string">"CLARK"</span>,
         <span class="hljs-attr">"JOB"</span>:<span class="hljs-string">"MANAGER"</span>,
         <span class="hljs-attr">"MGR"</span>:<span class="hljs-number">7839</span>,
         <span class="hljs-attr">"HIREDATE"</span>:<span class="hljs-string">"1981-06-09T00:00:00Z"</span>,
         <span class="hljs-attr">"SAL"</span>:<span class="hljs-number">2450</span>,
         <span class="hljs-attr">"DEPTNO"</span>:<span class="hljs-number">10</span>
      },
      {
         <span class="hljs-attr">"EMPNO"</span>:<span class="hljs-number">7839</span>,
         <span class="hljs-attr">"ENAME"</span>:<span class="hljs-string">"KING"</span>,
         <span class="hljs-attr">"JOB"</span>:<span class="hljs-string">"PRESIDENT"</span>,
         <span class="hljs-attr">"HIREDATE"</span>:<span class="hljs-string">"1981-11-17T00:00:00Z"</span>,
         <span class="hljs-attr">"SAL"</span>:<span class="hljs-number">5000</span>,
         <span class="hljs-attr">"DEPTNO"</span>:<span class="hljs-number">10</span>
      }
   ]
}
</code></pre>
<p>Now, you can have a Process or Dynamic Action to to save output to your audit table.</p>
<h3 id="heading-auditing-data-from-form-regions">Auditing Data from Form Regions</h3>
<p>You can also track data displayed via Form regions. Here’s an example of how to audit the Form region data.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">begin</span>
    <span class="hljs-keyword">for</span> set_items <span class="hljs-keyword">in</span> (<span class="hljs-keyword">select</span> item_name
                              <span class="hljs-keyword">from</span> apex_application_page_items
                              <span class="hljs-keyword">where</span> <span class="hljs-number">1</span> = <span class="hljs-number">1</span> 
                                <span class="hljs-keyword">and</span> application_id = v(<span class="hljs-string">'APP_ID'</span>)
                                <span class="hljs-keyword">and</span> page_id = v(<span class="hljs-string">'APP_PAGE_ID'</span>)
                                <span class="hljs-keyword">and</span> display_as != <span class="hljs-string">'Hidden'</span>)
    <span class="hljs-keyword">loop</span>

        <span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> your_audit_table (item_name, item_value, ...)
        <span class="hljs-keyword">values</span> (set_items.item_name, v(set_items.item_name), ...);

    <span class="hljs-keyword">end</span> <span class="hljs-keyword">loop</span>;

<span class="hljs-keyword">end</span>;
</code></pre>
<p>This PL/SQL block iterates through the form items, inserts each item's name and value into an audit table, and allows you to track the data displayed to the user.</p>
<p><strong>Enjoy auditing your APEX applications! :)</strong></p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX: How to Publish APEX (PWA) to the Google Play Store]]></title><description><![CDATA[Publishing your Oracle APEX Progressive Web App (PWA) to the Google Play Store can significantly increase your app’s visibility and accessibility. Here’s a simple guide to help you through the process.
Prerequisites
Before you start, ensure you have ...]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-how-to-publish-apex-pwa-to-the-google-play-store</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-how-to-publish-apex-pwa-to-the-google-play-store</guid><category><![CDATA[#oracle-apex]]></category><category><![CDATA[PWA]]></category><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Mon, 08 Jul 2024 22:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Z9fW8Nn7D24/upload/ad6da7fc7057c5efafb4b160e5a00528.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Publishing your Oracle APEX Progressive Web App (PWA) to the Google Play Store can significantly increase your app’s visibility and accessibility. Here’s a simple guide to help you through the process.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you start, ensure you have the following:</p>
<ol>
<li><p><strong>A Valid PWA</strong>: Your app must be a PWA with a web manifest and be accessible via HTTPS.</p>
</li>
<li><p><strong>Google Developer Account</strong>: Sign up for a Google developer account, which has a one-time fee of $25.</p>
</li>
<li><p><strong>UI/UX</strong>: Have a nice UI and UX in the app, otherwise app will be rejected.</p>
</li>
<li><p><strong>Follow Developer Content Policy</strong>: it is required to follow the polices from the following link <a target="_blank" href="https://play.google/developer-content-policy/">https://play.google/developer-content-policy/</a></p>
</li>
<li><p><strong>Android Device or Emulator</strong>: You need an Android device or emulator to test your app.</p>
</li>
<li><p><strong>Patience</strong>: before published - app might be rejected a few times by Google Play, asking for some additional information about your app.</p>
</li>
</ol>
<h2 id="heading-web-app-manifest">Web App Manifest</h2>
<p>The first thing to start with is the Web Manifest, where you can configure key details of your PWA app.</p>
<p>A web manifest is a JSON (JavaScript Object Notation) file that provides important configuration settings for a Progressive Web App (PWA). It plays a crucial role in defining how your web application should behave when installed on a user's device.</p>
<p>The manifest is crucial because it bridges the gap between a web app and a native app. By defining these settings, you ensure that your PWA behaves like a native app when installed, providing a seamless and engaging user experience. This consistency is key to user adoption and satisfaction.</p>
<p>Here are the key elements and their importance:</p>
<ol>
<li><p><strong>name</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: This is the full name of your web application.</p>
</li>
<li><p><strong>Importance</strong>: It is displayed to the user in various contexts, such as the app's title on the home screen and in the app launcher.</p>
</li>
</ul>
</li>
<li><p><strong>short_name</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: A shorter version of the app's name.</p>
</li>
<li><p><strong>Importance</strong>: Used where space is limited, such as on the device's home screen.</p>
</li>
</ul>
</li>
<li><p><strong>icons</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: An array of images representing different icon sizes for your app.</p>
</li>
<li><p><strong>Importance</strong>: Essential for providing a recognizable and professional appearance on different devices and screen resolutions. Recommended sizes include 192x192, 384x384, and 1024x1024 pixels.</p>
</li>
</ul>
</li>
<li><p><strong>theme_color</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: The color of the browser's UI elements when the app is launched.</p>
</li>
<li><p><strong>Importance</strong>: Enhances the user's experience by providing a consistent color theme.</p>
</li>
</ul>
</li>
<li><p><strong>background_color</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: The background color of the splash screen displayed when the app is launched.</p>
</li>
<li><p><strong>Importance</strong>: Improves the visual transition from the splash screen to the app.</p>
</li>
</ul>
</li>
<li><p><strong>display</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: Defines how the app should be displayed when launched.</p>
</li>
<li><p><strong>Options</strong>:</p>
<ul>
<li><p><strong>fullscreen</strong>: Suitable for games or apps that require maximum screen space.</p>
</li>
<li><p><strong>standalone</strong>: The most common setting, hides the URL bar, making the app look like a native app.</p>
</li>
</ul>
</li>
<li><p><strong>Importance</strong>: Determines the user interface and experience of the app.</p>
</li>
</ul>
</li>
<li><p><strong>start_url</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: The URL where the app should start when launched.</p>
</li>
<li><p><strong>Importance</strong>: Ensures that the app opens at the correct entry point.</p>
</li>
</ul>
</li>
<li><p><strong>orientation</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: Specifies the default orientation (portrait or landscape) for the app.</p>
</li>
<li><p><strong>Importance</strong>: Helps provide the best user experience by locking the app to the preferred orientation.</p>
</li>
</ul>
</li>
<li><p><strong>scope</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: Defines the navigation scope of the app, restricting which URLs the app can navigate to.</p>
</li>
<li><p><strong>Importance</strong>: Ensures that navigation stays within the app context.</p>
</li>
</ul>
</li>
<li><p><strong>description</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: A brief description of the web application.</p>
</li>
<li><p><strong>Importance</strong>: Provides users with an understanding of what the app does.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-example-of-a-web-manifest">Example of a Web Manifest</h3>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"myapp.com"</span>,
  <span class="hljs-attr">"short_name"</span>: <span class="hljs-string">"MyApp"</span>,
  <span class="hljs-attr">"icons"</span>: [
    {
      <span class="hljs-attr">"src"</span>: <span class="hljs-string">"icon-48x48.png"</span>,
      <span class="hljs-attr">"sizes"</span>: <span class="hljs-string">"48x48"</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"image/png"</span>
    },
    {
      <span class="hljs-attr">"src"</span>: <span class="hljs-string">"icon-48x48.png"</span>,
      <span class="hljs-attr">"sizes"</span>: <span class="hljs-string">"72x72"</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"image/png"</span>
    },
    ...
  ],
  <span class="hljs-attr">"theme_color"</span>: <span class="hljs-string">"#007bff"</span>,
  <span class="hljs-attr">"background_color"</span>: <span class="hljs-string">"#ffffff"</span>,
  <span class="hljs-attr">"display"</span>: <span class="hljs-string">"standalone"</span>,
  <span class="hljs-attr">"start_url"</span>: <span class="hljs-string">"/"</span>,
  <span class="hljs-attr">"orientation"</span>: <span class="hljs-string">"portrait"</span>,
  <span class="hljs-attr">"scope"</span>: <span class="hljs-string">"/"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Description of the app"</span>
}
</code></pre>
<p>More about app Manifest - <a target="_blank" href="https://www.w3.org/TR/appmanifest/">https://www.w3.org/TR/appmanifest/</a></p>
<p>In APEX, you can add it by navigating to <strong>Shared Components &gt; Progressive Web App &gt; Custom Manifest</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719751277098/26118541-3b4a-4c29-87b3-7d611fa0d399.png" alt="Custom Manifest in Oracle APEX" class="image--center mx-auto" /></p>
<h2 id="heading-packaging-your-pwa-app">Packaging Your PWA App</h2>
<p>To package the PWA into an Android app, I will use PWABuilder, which simplifies the process for us. Follow these steps to package the APEX app using PWABuilder.</p>
<h3 id="heading-pwabuilder">PWABuilder</h3>
<p>This powerful tool is designed to simplify the process of converting Progressive Web Apps (PWAs) into platform-specific apps, such as those for Android, iOS, Microsoft and Meta Quest. Created by Microsoft, PWABuilder offers an intuitive and straightforward way for developers to package their web applications and make them available across various app stores, enhancing the app's accessibility and user reach.</p>
<ol>
<li><p><strong>Visit PWABuilder</strong>: Go to <a target="_blank" href="https://www.pwabuilder.com">PWABuilder.com</a>.</p>
</li>
<li><p><strong>Enter Your PWA URL</strong>: Input the URL of your PWA and click Start button.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719913990800/df53fb35-45ec-41ac-9835-17941ae225d5.png" alt="PWABuilder Home Page" class="image--center mx-auto" /></p>
<ol start="3">
<li><strong>Select Packaging Option</strong>: Click "Package for stores".</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719914111191/2434dbcb-b41c-4ff2-9c16-8594cfc019c8.png" alt="PWABuilder - Package For Stores" class="image--center mx-auto" /></p>
<ol start="4">
<li><strong>Generate Android Package</strong>: Choose "Generate Package" under the Android section.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719914202312/3c654697-a9a7-44f0-afa1-f95b38487913.png" alt="PWABuilder - Generate Package" class="image--center mx-auto" /></p>
<ol start="5">
<li><strong>Configure Package Options</strong>: On the Google Play tab, fill out the necessary information. Check if all the settngs under "All Settings" is correct.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719914540594/035ef9a1-cb25-45eb-b303-b19c7a18b481.png" alt="PWABuilder - Andriod Package Options" class="image--center mx-auto" /></p>
<ol start="6">
<li><strong>Download Package</strong>: Click "Download Package" to get your Android package.</li>
</ol>
<div data-node-type="callout">
<div data-node-type="callout-emoji">❗</div>
<div data-node-type="callout-text">Ensure your package ID is unique. If you get the same package ID that already exist for some of your apps e.g. <code>com.myapp.www.twa</code>, modify it to e.g. <code>com.myapp.www.twa.pwa</code>.</div>
</div>

<h2 id="heading-publishing-your-pwa-app">Publishing Your PWA App</h2>
<h3 id="heading-1-deploy-assetlinksjson">1. Deploy assetlinks.json</h3>
<p>Under PWABuilder .zip, you will find - <code>assetlinks.json</code> is a JSON file used to establish a relationship between your PWA and your website. It proves that you own the domain from which your PWA is served and allows the PWA to be installed without the browser URL bar, making it look more like a native app.</p>
<p>Upload the <code>assetlinks.json</code> file to your web server to prove ownership of your PWA. Place this file in the public folder of your server, making it accessible at <code>https://&lt;URL to your PWA&gt;/.well-known/assetlinks.json</code>.</p>
<h3 id="heading-key-elements-of-assetlinksjson">Key Elements of assetlinks.json</h3>
<ol>
<li><p><strong>relation</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: Specifies the permissions or actions that are allowed.</p>
</li>
<li><p><strong>Importance</strong>: Ensures the PWA has the necessary permissions, such as handling all URLs related to the domain.</p>
</li>
</ul>
</li>
<li><p><strong>target</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: Defines the target app and its properties.</p>
</li>
<li><p><strong>Importance</strong>: Establishes the connection between your web app and the Android app package.</p>
</li>
</ul>
</li>
</ol>
<p>    Within the <code>target</code>, there are several important fields:</p>
<ul>
<li><p><strong>namespace</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: Identifies the type of target. For Android apps, this is always <code>"android_app"</code>.</p>
</li>
<li><p><strong>Importance</strong>: Confirms the target is an Android application.</p>
</li>
</ul>
</li>
<li><p><strong>package_name</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: Specifies the package name of the Android app.</p>
</li>
<li><p><strong>Importance</strong>: Uniquely identifies your app in the Play Store.</p>
</li>
</ul>
</li>
<li><p><strong>sha256_cert_fingerprints</strong>:</p>
<ul>
<li><p><strong>Purpose</strong>: Lists SHA-256 fingerprints of the app’s signing certificate.</p>
</li>
<li><p><strong>Importance</strong>: Ensures the app is securely linked to your web domain.</p>
</li>
</ul>
</li>
</ul>
<p><strong>Example of assetlinks.json</strong></p>
<pre><code class="lang-json">[
  {
    <span class="hljs-attr">"relation"</span>: [<span class="hljs-string">"delegate_permission/common.handle_all_urls"</span>],
    <span class="hljs-attr">"target"</span>: {
      <span class="hljs-attr">"namespace"</span>: <span class="hljs-string">"android_app"</span>,
      <span class="hljs-attr">"package_name"</span>: <span class="hljs-string">"com.myapp.www"</span>,
      <span class="hljs-attr">"sha256_cert_fingerprints"</span>: [
        <span class="hljs-string">"SHA256"</span>,
        <span class="hljs-string">"SHA256"</span> <span class="hljs-comment">// to be replaced later for production </span>
      ]
    }
  }
]
</code></pre>
<h3 id="heading-2-upload-app-to-google-play-store">2. Upload App to Google Play Store</h3>
<ol>
<li><p><strong>Log into the Google Play Console</strong>: Sign in and create a new app, providing the app name and other details.</p>
</li>
<li><p><strong>Complete Dashboard Tasks</strong>: Follow the tasks listed on the Dashboard page. It will ask for some details of your app.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719913400870/29ab4d9c-bc93-4917-9037-e90d8595b5c1.png" alt="Google Play - Dashboard tasks" class="image--center mx-auto" /></p>
<ol start="3">
<li><p><strong>Create a New Release</strong>: Under Internal Testing &gt; New Release. In the release creation step, you’ll need to upload an Android App Bundle (.aab) file from the zip file downloaded from PWABuilder.</p>
</li>
<li><p><strong>Generate Google Signing Key</strong>: Follow the prompts to generate this key.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719995953159/cfc43ca9-88c5-4c59-9ec2-d824b2ecd2d9.png" alt class="image--center mx-auto" /></p>
<ol start="5">
<li><p><strong>Prepare app screenshots</strong>: You will need app screenshots for different devices, that will be listed on the Play Store.</p>
</li>
<li><p><strong>Add Testers</strong>: You’ll be asked to add Gmail accounts for internal testers, so App will be available for those account on the Play Store.</p>
</li>
</ol>
<h3 id="heading-3-update-assetlinksjson-for-production">3. Update assetlinks.json For Production</h3>
<ol>
<li><p><strong>Copy SHA-256 String</strong>: Go to the App Signing page in the Google Play Console and copy the SHA-256 string. <strong>Menu &gt; Setup &gt; App Signing &gt; Copy - SHA-256 certificate fingerprint</strong></p>
</li>
<li><p><strong>Add SHA-256 to</strong><code>assetlinks.json</code>:</p>
<pre><code class="lang-javascript"> [
   {
     <span class="hljs-string">"relation"</span>: [<span class="hljs-string">"delegate_permission/common.handle_all_urls"</span>],
     <span class="hljs-string">"target"</span>: {
       <span class="hljs-string">"namespace"</span>: <span class="hljs-string">"android_app"</span>,
       <span class="hljs-string">"package_name"</span>: <span class="hljs-string">"com.myapp.www"</span>,
       <span class="hljs-string">"sha256_cert_fingerprints"</span>: [
         <span class="hljs-string">"OLD_SHA"</span>,
         <span class="hljs-string">"NEW_ONE"</span>
       ]
     }
   }
 ]
</code></pre>
<h3 id="heading-testing-the-app-for-14-days">Testing the App For 14 Days</h3>
<p> Before applying for the production, Google will ask you for 20 testers that will test your app for 14 days, so it might be your employees, friends, family... a bit boring.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719913636193/2af39a38-2019-4848-ade5-937292224e6d.png" alt="Google Play - 20 testers" class="image--center mx-auto" /></p>
<h2 id="heading-application-is-on-play-store">Application is on Play Store</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1719761091306/0c210d4e-8e0f-4470-82d5-7311b26434f3.jpeg" alt="Oracle APEX application on Google Play Store" class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX: Calendar Options You Might Not Know About]]></title><description><![CDATA[Recently, I've been checking out the FullCalendar documentation and found some interesting options that might be useful. Whether you're new to FullCalendar or already familiar, these tips might make your experience even better.
FullCalendar
Oracle AP...]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-calendar-options-you-might-not-know-about</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-calendar-options-you-might-not-know-about</guid><category><![CDATA[#oracle-apex]]></category><category><![CDATA[FullCalendar]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[calendar]]></category><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Thu, 28 Mar 2024 12:43:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/bwOAixLG0uc/upload/9161f2d41d8dcd851110ebbcea4c42d8.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, I've been checking out the FullCalendar documentation and found some interesting options that might be useful. Whether you're new to FullCalendar or already familiar, these tips might make your experience even better.</p>
<h3 id="heading-fullcalendar">FullCalendar</h3>
<p>Oracle APEX has a region type called Calendar, which is using the FullCalendar library. Full Calendar is powerfull lightweight library with over 300 settings, and more being added every release. Some of settings are nativly included in APEX, but for some advanced settings, Initialization JavaScript Function is needed to override/set the options.</p>
<p>Feel free to explore documentation and available options <a target="_blank" href="https://fullcalendar.io/docs">here</a>.</p>
<p>Place to add your Initialization JavaScript Function in APEX is <strong>Calendar region &gt; Attributes &gt; Initialization JavaScript Function</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710628733616/c1b96ac8-9ef7-46f7-8cdf-8b6437059d25.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-options">Options</h3>
<ul>
<li><strong>Custom Button</strong></li>
</ul>
<p>If you have any need to create a custom button to your Calendar region, and add the action to it, this option is for you. :)</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"> pOptions </span>) </span>{             

    pOptions.headerToolbar = {
        <span class="hljs-attr">start</span>: <span class="hljs-string">'myCustomButton'</span>, 
        <span class="hljs-attr">center</span>: <span class="hljs-string">''</span>,
        <span class="hljs-attr">end</span>: <span class="hljs-string">'today prev,next'</span> 
    }

    pOptions.customButtons = {
        <span class="hljs-attr">myCustomButton</span>: {
        <span class="hljs-attr">text</span>: <span class="hljs-string">'Custom Button!'</span>,
        <span class="hljs-attr">click</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
            alert(<span class="hljs-string">'Button Clicked!'</span>);
        }
        }
    }

    <span class="hljs-keyword">return</span> pOptions;
}
</code></pre>
<p>The options above will create a custom button to the beginning of the calendar's header. Clicking the button will trigger an alert message.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711627663896/98566dcf-96f9-4c5f-8ec5-bae5ab2d9835.gif" alt class="image--center mx-auto" /></p>
<ul>
<li><strong>eventDrop</strong></li>
</ul>
<p>My favorite feature of the FullCalendar is drag and drop functionality, sometimes you might need to ask user to confirm their action on the Calendar. Here is how you can do that.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"> pOptions </span>) </span>{ 

    pOptions.eventDrop = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">info</span>) </span>{

        <span class="hljs-keyword">if</span> (!confirm(info.event.title + <span class="hljs-string">" was dropped on "</span> + info.event.start.toISOString())) {
            info.revert();
        }
    }

    <span class="hljs-keyword">return</span> pOptions;
}
</code></pre>
<p>If I try to drag an event, I will get an confirm dialog.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711629572864/cda03a74-04e5-4cb7-83ba-56d7215cd165.gif" alt class="image--center mx-auto" /></p>
<ul>
<li><strong>eventContent</strong></li>
</ul>
<p>If you want to add an additional text, image or any HTML to your event, without turning Escape special characters to off <strong>eventContent</strong> option might be helpful.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"> pOptions </span>) </span>{ 

    pOptions.eventContent = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">arg</span>) </span>{
      <span class="hljs-keyword">return</span> {
        <span class="hljs-attr">html</span>: arg.event.title + <span class="hljs-string">'&lt;i&gt;your html code here&lt;/i&gt;'</span>
      }
    }

    <span class="hljs-keyword">return</span> pOptions;
}
</code></pre>
<p>As you can see in the image below, next to the title we will get an italic text that is used in Initialization Function.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711629691351/23f7de96-5aa9-40bc-9a3b-6f7fe99bb6dc.png" alt class="image--center mx-auto" /></p>
<ul>
<li><strong>hiddenDays</strong></li>
</ul>
<p>To hide certain days in the calendar, you can use hiddenDays option, providing week days in range from 0 to 6 as an array.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"> pOptions</span>) </span>{
    pOptions.hiddenDays = [<span class="hljs-number">1</span>, <span class="hljs-number">3</span>]; <span class="hljs-comment">// hides Monday and Wednesday</span>

    <span class="hljs-keyword">return</span> pOptions;
}
</code></pre>
<p>The Calendar image below shows that Monday and Wednesday are not displayed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711629113454/cc1145f9-a671-488f-84f8-858a628c9623.png" alt class="image--center mx-auto" /></p>
<ul>
<li><strong>validRange</strong></li>
</ul>
<p>To set a start and end dates of the Calendar, we can use validRange option. So the user will not be able to navigate outside of the provided range.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"> pOptions</span>) </span>{ 

    pOptions.validRange = {
        <span class="hljs-attr">start</span>: <span class="hljs-string">'2024-02-01'</span>,
        <span class="hljs-attr">end</span>: <span class="hljs-string">'2024-05-01'</span>
    }

    <span class="hljs-keyword">return</span> pOptions;
}
</code></pre>
<h3 id="heading-conclusion">Conclusion</h3>
<p>I hope you find these options useful. All or some of the options will be integrated into our Component Designer tool. Keep an eye out for updates! :)</p>
<p>And don't forget to explore the <a target="_blank" href="https://apex.oracle.com/pls/apex/r/rittmanmead/apex-component-designer/components?">Component Designer</a> tool—it's a valuable resource for designing and generating JavaScript Initialization Code tailored for Oracle APEX Components. Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX: Auto-refresh Report]]></title><description><![CDATA[Recently I have discussed creating an auto refresh report within APEX with Lucas, the idea is to display Classic Report, and refresh it every n seconds whilst also visually show user when the next refresh will happen. This dynamic approach ensures th...]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-auto-refresh-report</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-auto-refresh-report</guid><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Wed, 17 Jan 2024 11:10:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1705490334229/524a6721-4668-4eaf-bcd3-9378c8911893.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently I have discussed creating an auto refresh report within APEX with <a target="_blank" href="https://www.linkedin.com/in/lucashirschegger/">Lucas</a>, the idea is to display Classic Report, and refresh it every n seconds whilst also visually show user when the next refresh will happen. This dynamic approach ensures that users have access to the most up-to-date information without manual intervention.</p>
<p>These kinds of reports can prove to be quite handy. They not only provide users with real-time updates but also enhance the overall user experience by ensuring that the displayed information remains current and relevant. This feature can be particularly beneficial in dynamic environments where data is constantly changing. By refreshing the Classic Report at regular intervals, we keep users well-informed and engaged with the latest data and trends in a user-friendly manner.</p>
<p>I will break this down into steps, making it easier to follow.</p>
<h3 id="heading-step-1-create-a-progress-bar-in-classic-report"><strong>Step 1 - Create a progress bar in Classic Report</strong></h3>
<p>I will assume that you already have a Classic Report with data that you want to refresh. If not then simple create one, give the static id (in my case I called it empRpt. This id is needed later on).</p>
<p>Firstly, we will add CSS class to the header of the report, that will incorporate a progress bar into the Classic Report header, which will visually indicate when the next refresh will occur.</p>
<p>Navigate to your CR (Classic Report) &gt; Region &gt; Header and Footer &gt; Header, and add the following HTML.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"progress-bar"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"u-flex w100p h5 progress"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705485430500/2809ba5f-6772-4a63-b442-c514fbceb785.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-step-2-create-after-refresh-dynamic-action">Step 2 - Create After Refresh Dynamic Action</h3>
<p>We are now going to create a Dynamic Action that will continually refresh the report. The event type to choose is "After Refresh" and the region that is related to your Classic Report.</p>
<p>Ensure that the After Refresh DA on the CR, where event scope is set to <strong>Dynamic,</strong> type is set to <strong>Debounce</strong> and time to <strong>5000ms</strong> (5s).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705485424692/0fa6692a-6aa2-4170-a4f8-c78be6caaf8a.png" alt class="image--center mx-auto" /></p>
<p>Now, we need an Action, for this choose Execute JavaScript Code and enter the following.</p>
<pre><code class="lang-javascript">$(<span class="hljs-string">"#progress-bar"</span>).removeClass(<span class="hljs-string">"progress"</span>).promise().then(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    apex.region(<span class="hljs-string">"empRpt"</span>).refresh().promise();
}).then(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    $(<span class="hljs-string">"#progress-bar"</span>).addClass(<span class="hljs-string">"progress"</span>);
});
</code></pre>
<p>The provided code ensures that the 'progress' class is removed before refreshing the region with the Static ID "empRpt". After the region is refreshed, the 'progress' class is added back, ensuring that the progress is displayed again post-refresh.</p>
<p>Make sure that <strong>Fire on Initialization</strong> is set to <strong>Yes</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705487169503/4074b4e7-69fc-4801-999f-f3ddcaea0f30.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-final-step-3-create-css-animation">Final Step 3 - Create CSS animation</h3>
<p>Create a progress bar animation, so user can see when next refresh will happen. Add the CSS snippet below to Page &gt; Inline</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.progress</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--u-color-<span class="hljs-number">1</span>);
    <span class="hljs-attribute">animation</span>: progressBar <span class="hljs-number">5s</span> ease-in-out;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">5px</span>;
}

<span class="hljs-keyword">@keyframes</span> progressBar {
  0% { <span class="hljs-attribute">width</span>: <span class="hljs-number">0</span>; }
  100% { <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705488254004/30fd98f4-3d72-4d64-9df1-cb542b2d9895.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-result">Result</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705488668244/cc236996-4704-42ab-a5ce-88334021b68f.gif" alt class="image--center mx-auto" /></p>
<p>Thanks a lot to <a target="_blank" href="https://www.linkedin.com/in/lucashirschegger/">Lucas Hirschegger</a> for the idea and help.</p>
<h3 id="heading-in-conclusion">In Conclusion</h3>
<p>This straightforward implementation, featuring a progress bar and refreshing the Classic Report every 5 seconds, significantly enhances the user experience by providing a clear visual indicator of the refresh process. The progress bar is a subtle yet effective element in guiding users through the refresh cycle, contributing to a smoother and more engaging experience.</p>
<p>Hope you and your users find this enhancement valuable! :)</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX: Save User Preference With Browser Storage]]></title><description><![CDATA[Recently, while experimenting with browser storage, I came up with an idea on how to eliminate that boring message, that clients generally don't like: "This page is asking you to confirm that you want to leave—information you’ve entered may not be sa...]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-save-user-preference-with-browser-storage</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-save-user-preference-with-browser-storage</guid><category><![CDATA[#oracle-apex]]></category><category><![CDATA[orclapex]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Tue, 02 Jan 2024 08:15:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/82TpEld0_e4/upload/79199f6bf2ded2a7b93e26f404246069.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, while experimenting with browser storage, I came up with an idea on how to eliminate that boring message, that clients generally don't like: "<strong>This page is asking you to confirm that you want to leave—information you’ve entered may not be saved</strong>".</p>
<p>The concept is to save what the user enters on the page in the browser storage. This way, even if the user is in a new session the next time they visit the page, the information will be stored and can be loaded seamlessly.</p>
<p>To address this, I will utilize browser storage to store the preferred value in local storage. This way, the application can reuse saved value every time the user logs in.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><mark>Note: do not save sensitive data into browser storage</mark></div>
</div>

<h3 id="heading-browser-storage">Browser Storage</h3>
<p>Think of browser storage as a virtual backpack for the internet. It allows websites keep and remember information directly on your device. There are two main types of browser storage – Local Storage and Session Storage.</p>
<p><strong>Local Storage</strong> is like a long-term memory bank. Whatever you store here stays even after you close your browser. It's great for saving things like preferences, item values or any data you want to keep between different visits.</p>
<p><strong>Session Storage</strong> is more like a short-term memory. It only keeps data for as long as you have a particular webpage open. Once you close that webpage or tab, the stored information disappears. It's handy for temporary data needs.</p>
<p>Why is browser storage important? By smartly using these storage options, you can make your application work better. You can create personalized experiences for users and make your app work better. The possibilities are endless when you make the most of browser storage.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">The storage capacity for localStorage and sessionStorage is 5-10MB, significantly larger than the 4KB limit for Cookies.</div>
</div>

<h3 id="heading-how-does-it-work-with-apex">How does it work with APEX?</h3>
<p>Since APEX supports multiple applications, workspaces and even the same application working on different instances. There might be a problem using the browser storage because all apps from the same instance are using the same browser storage. To avoid that <code>apex.storage.getScopedLocalStorage</code> and <code>apex.storage.getScopedSessionStorage</code> is partitioning the storage by application id, additionally, page id and region id.</p>
<p>Given that APEX supports multiple applications, workspaces, and the possibility of the same application running on different instances, there's a potential issue with using browser storage. The problem arises when all apps from the same instance share the same browser storage. To address this challenge in the APEX, there are APIs: <code>apex.storage.getScopedLocalStorage</code> and <code>apex.storage.getScopedSessionStorage</code>. These methods act as a partitioning mechanism, ensuring that the storage is separated based on the application ID. Moreover, they take into account the page ID and region ID, providing a more granular and isolated storage environment for each specific instance of an application.</p>
<p>For more details, check official <a target="_blank" href="https://docs.oracle.com/en/database/oracle/application-express/18.2/aeapi/apex-storage-namespace.html#GUID-4C180D70-B693-4250-AB28-B1B8D647B3B2">documentation</a>.</p>
<h3 id="heading-browser-comaptibility">Browser Comaptibility</h3>
<p><strong>sessionStorage</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704182684479/6aa0d84a-5b8f-46ea-aae2-94688eeb740c.png" alt class="image--center mx-auto" /></p>
<p><strong>localStorage</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1704182727219/b5782b99-7dc2-4b8b-bc8a-a410e5670921.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-implementation">Implementation</h3>
<p>First, let's create a page item, and call it PX_BLOG.</p>
<p>The next step would be to create a dynamic action, that fires on page unload (when the user leaves the page). It should execute JavaScript code that saves our item text to local storage.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">if</span> ( apex.storage.hasLocalStorageSupport() ) {
  <span class="hljs-built_in">localStorage</span> = apex.storage.getScopedLocalStorage({ <span class="hljs-attr">prefix</span>: <span class="hljs-string">"Demo"</span>, 
                                                      <span class="hljs-attr">useAppId</span>: <span class="hljs-literal">true</span>,
                                                      <span class="hljs-attr">usePageId</span>: <span class="hljs-literal">true</span> });
  <span class="hljs-built_in">localStorage</span>.setItem( <span class="hljs-string">"text"</span>,  <span class="hljs-built_in">JSON</span>.stringify($v(<span class="hljs-string">"P2_BLOG"</span>)) );
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702996370008/8329b0cd-dbd5-4510-8148-d42028bc388d.png" alt class="image--center mx-auto" /></p>
<p>Now, when a user types something in <code>P4_BLOG</code> item and left the page, the value of the item is written in the local storage.</p>
<p>To check if the value is set, run the following code in your browser console.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> itemText = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">'text'</span>);
<span class="hljs-built_in">console</span>.log(itemText);
</code></pre>
<p>The next step is to create Dynamic Action that fires on page load, to set the value of the P4_BLOG with the value from the local storage.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> itemText;

<span class="hljs-keyword">if</span> ( apex.storage.hasLocalStorageSupport() ) {
  itemText = apex.storage.getScopedLocalStorage({ <span class="hljs-attr">prefix</span>: <span class="hljs-string">"Demo"</span>, 
                                                  <span class="hljs-attr">useAppId</span>: <span class="hljs-literal">true</span>,
                                                  <span class="hljs-attr">usePageId</span>: <span class="hljs-literal">true</span> });
  itemText = <span class="hljs-built_in">localStorage</span>.getItem( <span class="hljs-string">"text"</span> );
}

$s(<span class="hljs-string">'P4_BLOG'</span>, <span class="hljs-built_in">JSON</span>.parse(itemText))
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702996398042/1bf40e0c-d6ef-448a-b6dd-8f206e7ccb14.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-result">Result</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702994690651/24237bcc-3b75-4335-b333-c39d86f79b82.gif" alt class="image--center mx-auto" /></p>
<p>Check out the demo <a target="_blank" href="https://apex.oracle.com/pls/apex/r/oracle_forum/browser-storage/home?session=110709070823962">application</a>.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Browser Storage is a great way to save data that might be used in the app as a session based storage or use it even after the session is ended!</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX UT: Visibility Classes]]></title><description><![CDATA[To continue my Universal Theme series, I am writing about Visibility Classes – another set of powerful classes that will help you adapt your apps to different screen sizes and ensure the safety of upgrading your applications.
The Universal Theme como...]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-ut-visibility-classes</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-ut-visibility-classes</guid><category><![CDATA[orclapex]]></category><category><![CDATA[Oracle]]></category><category><![CDATA[PWA]]></category><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Mon, 25 Dec 2023 12:59:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1700502993568/31d0900c-8aad-4a51-b91e-4a8b9716e64e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>To continue my Universal Theme series, I am writing about Visibility Classes – another set of powerful classes that will help you adapt your apps to different screen sizes and ensure the safety of upgrading your applications.</p>
<p>The Universal Theme comopnents are optimised to work well on different screen sizes, but not every APEX component is mobile-friendly; for instance, some reports might be challenging for users to read on mobile devices due to potential large horizontal scrolling.</p>
<p>Visibility classes are utilized to regulate when components should be hidden or displayed, based on the specific width range of the screen viewport.</p>
<h3 id="heading-mobile-friendly-components">Mobile-friendly components</h3>
<p>As I mentioned already, some UT (Universal Theme) APEX components are not mobile-friendly. Such as Interactive Report, Interactive Grid and Classic Report</p>
<p>Oracle APEX has three mobile-friendly reports: a List View, Column Toggle, and a Reflow Report.</p>
<ul>
<li><p><strong>List View</strong>: A List View report is like a mobile-friendly table that shows data neatly and lets you move around easily on your phone. It takes information from a specified data source (either local or external) and a table or SQL query you provide. Developers use the report attributes to pick which database columns to show, including the one used for List View entry.</p>
</li>
<li><p><strong>Column Toggle Report</strong>: This report is another way to display data from a SQL query, either local or external. It includes a handy "Columns" button that lets users choose which columns they want to see.</p>
</li>
<li><p><strong>Reflow</strong> <strong>Report</strong>: Think of a Reflow Report as a smart table that adjusts when there's not enough space to show everything side by side. It takes data from your chosen source, and if the space is tight, it rearranges the table into a neat vertical layout, displaying each column on its own row.</p>
</li>
</ul>
<h3 id="heading-problem">Problem</h3>
<p><strong>Classic Report -</strong> is displayed well on desktop, but on mobile, the problem is a big horizontal scroll and it is not easy to read what is on the report, especially when there's a column with large text.</p>
<p>Screenshot of the CR on the desktop. Columns are displayed as they should, and it looks nice.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701244868033/df9f7226-a45f-46c7-ac73-4cc886032cd0.png" alt class="image--center mx-auto" /></p>
<p>Below is the same report displayed on the mobile.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702987312878/8d6c0afc-5f55-4bcb-bbc3-bf88942c435f.png" alt class="image--center mx-auto" /></p>
<p>As you can see from the screenshot above, only three columns are displayed, and the user needs to scroll horizontally to see the rest, if there is a column such as a description it might be even worse.</p>
<h3 id="heading-solution">Solution</h3>
<p>Universal Theme provides CSS classes that we can use to display or hide elements depending on the screen width.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701268872156/94245717-d32e-44fe-bfb7-0b87992830ee.png" alt class="image--center mx-auto" /></p>
<p>So take a look at the screenshot above, for instance the class <strong>hidden-sm-down</strong> means that the component will be hidden on the screen width of 767px and below, but will be displayed on any screen wider than 767px.</p>
<p>Let's hide Classic Report on the smaller screens and display Reflow Report instead.</p>
<p>First, we need to create a Classic Report and assign the class <strong>hidden-sm-down</strong> to the CR, which means that it will be hidden on the screen size below 767px.</p>
<p>Next, we need another report to be displayed on the screen size below 767px and hidden on the screen size above 767px. So create the Reflow Report and assign <strong>hidden-sm-up</strong> class, which is the opposite of <strong>hidden-sm-down</strong>.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">❗</div>
<div data-node-type="callout-text">Note: classes should be added to Column CSS Classes under the Layout section in the property editor.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702554945942/666c355c-c722-4003-9805-66fc87dc031c.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-results">Results</h3>
<p>Here is the result where you can see how the report is changing depending on the screen size. Take a look at the classes at the top of the CR/Reflow Report.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702558081437/567c7d17-01eb-46c0-b513-ac3b01f539db.gif" alt class="image--center mx-auto" /></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Visibility Classes is the feature you will like if you are developing mobile applications with Oracle APEX. For more details about the Visbility Classes check the Universal Theme <a target="_blank" href="https://apex.oracle.com/pls/apex/r/apex_pm/ut/grid-layout?request=responsive_design">app</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX: IG Options You Might Not Know About]]></title><description><![CDATA[While seeking ways to improve our Oracle APEX Component Designer, I discovered some useful features in the Interactive Grid documentation. I’ll give you a quick rundown in this blog, and you can look forward to seeing them soon in our APEX Component ...]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-ig-options-you-might-not-know-about</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-ig-options-you-might-not-know-about</guid><category><![CDATA[interactive-grid]]></category><category><![CDATA[#oracle-apex]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Fri, 08 Dec 2023 08:50:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702030562986/ccbc2832-15df-4376-8d16-fcf73da66eba.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While seeking ways to improve our Oracle APEX Component Designer, I discovered some useful features in the Interactive Grid documentation. I’ll give you a quick rundown in this blog, and you can look forward to seeing them soon in our APEX <a target="_blank" href="https://www.rittmanmead.com/blog/2023/09/apex-component-designer/">Component Designer</a> tool.</p>
<h3 id="heading-options">Options</h3>
<ul>
<li><strong>reorderColumns</strong></li>
</ul>
<p>It can be annoying for users if they accidentally change the order of a column in the IG. By default, users can click on the left edge of a column and move it to a different spot in the IG. To prevent this, we have a "reorderColumns" option. The default is set to <code>true</code> meaning users can move columns around. But if you want to disable that option, you can set it to <code>false</code>.</p>
<p>Behaviour when <code>reorderColumns</code> is enabled.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702020398581/307f3e03-ba8f-4c4b-8575-0f2db3309b19.gif" alt="Interactive Grid reoder columns" class="image--center mx-auto" /></p>
<p>After setting <code>reorderColumns</code> to false, the option is disabled, so the user is not able to reorder the columns.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702020713015/61acc21d-2638-47df-be7d-1b84d3050c6d.gif" alt="Interactive Grid reorder columns" class="image--center mx-auto" /></p>
<p>The code for <code>reorderColumn</code> option.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">options</span>) </span>{

    options.defaultGridViewOptions = {
       <span class="hljs-attr">reorderColumns</span>: <span class="hljs-literal">false</span>
}

 <span class="hljs-keyword">return</span> options;
}
</code></pre>
<ul>
<li><strong>skipReadonlyCells</strong></li>
</ul>
<p>When users edit the IG, they use the tab key to move between columns. If you have columns that can't be edited (read-only), the tab key still goes there. To avoid this and skip read-only cells, you can set the "skipReadonlyCells" option to <code>true</code>. The default setting is <code>false</code>.</p>
<p>The behaviour after setting <code>skipReadonlyCells</code> to <code>true</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702021027814/1dcc7bee-96e4-4ff5-94d6-bddcf88ae43a.gif" alt="skip read-only field Interactive Grid" class="image--center mx-auto" /></p>
<p>The code for <code>skipReadonlyCells</code> option.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">options</span>) </span>{

    options.defaultGridViewOptions = {
       <span class="hljs-attr">skipReadonlyCells</span>: <span class="hljs-literal">true</span>
}

 <span class="hljs-keyword">return</span> options;
}
</code></pre>
<ul>
<li><strong>footer</strong></li>
</ul>
<p>If you don't want to show the footer of the IG, perhaps because there are only a few rows to display, you can use the <code>footer</code> option. Set it to <code>false</code> to hide the footer. The default setting is <code>true</code>.</p>
<p>The look after disabling the <code>footer</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702021626437/12de5a14-543f-495d-b69a-85f58e1125a0.png" alt="Interactive Grid without footer" class="image--center mx-auto" /></p>
<p>The code for the <code>footer</code> option.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">options</span>) </span>{

    options.defaultGridViewOptions = {
       <span class="hljs-attr">footer</span>: <span class="hljs-literal">false</span>
}

 <span class="hljs-keyword">return</span> options;
}
</code></pre>
<ul>
<li><strong>hideEmptyFooter</strong></li>
</ul>
<p>In case you want to display the footer, but not when no data found message is shown. The option <code>hideEmptyFooter</code> is available to hide the footer.</p>
<p>The behaviour of the <code>hideEmptyFooter</code> option.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702021925461/3a92c81c-a990-496d-be60-924265d811a8.gif" alt="Interactive Grid, without footer when no data found" class="image--center mx-auto" /></p>
<p>The code for the <code>hideEmptyFooter</code> option.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">options</span>) </span>{

    options.defaultGridViewOptions = {
       <span class="hljs-attr">hideEmptyFooter</span>: <span class="hljs-literal">true</span>
}

 <span class="hljs-keyword">return</span> options;
}
</code></pre>
<ul>
<li><strong>noDataIcon</strong></li>
</ul>
<p>If you want to change the icon displayed when there's no data found in the IG, you can use the <code>noDataIcon</code> option and provide the icon name as the value.</p>
<p>Look at the new icon, when no data is found.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702022120961/80e53df4-d9a0-452f-ba43-795c48cdefff.png" alt="Interactive Grid no data found Icon" class="image--center mx-auto" /></p>
<p>The code for the <code>noDataIcon</code> option.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">options</span>) </span>{

    options.defaultGridViewOptions = {
       <span class="hljs-attr">noDataIcon</span>: <span class="hljs-string">"fa fa-404"</span>
}

 <span class="hljs-keyword">return</span> options;
}
</code></pre>
<ul>
<li><strong>hideDeletedRows</strong></li>
</ul>
<p>Another interesting option is <code>hideDeletedRows</code>. When you delete a row in the IG, the row is typically still visible until you click the Save button. However, if there's a reason to hide it immediately, this option is supported.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702022442122/8a54619f-a327-4f33-9a17-e0f7c2d3e672.gif" alt="Interactive Grid hide deleted rows" class="image--center mx-auto" /></p>
<p>The code for the <code>hideDeletedRows</code> option.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">options</span>) </span>{

    options.defaultGridViewOptions = {
       <span class="hljs-attr">hideDeletedRows</span>: <span class="hljs-literal">true</span>

 <span class="hljs-keyword">return</span> options;
}
</code></pre>
<ul>
<li><strong>pagination</strong></li>
</ul>
<p>To have more control over your pagination, you can utilize the <code>pagination</code> option.</p>
<p>The configuration shown in the image below removes links and buttons, resulting in the footer displaying only the count and the number of selected rows.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702022777713/00ac036f-903a-45dc-981f-1b3b509a9a7f.png" alt="Interactive Grid pagination options" class="image--center mx-auto" /></p>
<p>The code for the <code>pagination</code> option.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">options</span>) </span>{

    options.defaultGridViewOptions = {
       <span class="hljs-attr">pagination</span>: {
        <span class="hljs-attr">showRange</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">showPageLinks</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">maxLinks</span>: <span class="hljs-number">0</span>,
        <span class="hljs-attr">firstAndLastButtons</span>: <span class="hljs-literal">false</span>
      }
}

 <span class="hljs-keyword">return</span> options;
}
</code></pre>
<p>To discover more details about the options mentioned above, refer to the official documentation - <a target="_blank" href="https://docs.oracle.com/en/database/oracle/apex/23.2/aexjs/grid.html">docs</a>.</p>
<h3 id="heading-code-example-for-all-the-options"><strong>Code Example for all the options</strong></h3>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">options</span>) </span>{

    options.defaultGridViewOptions = {
       <span class="hljs-attr">reorderColumns</span>: <span class="hljs-literal">false</span>,
       <span class="hljs-attr">skipReadonlyCells</span>: <span class="hljs-literal">true</span>,
       <span class="hljs-attr">footer</span>: <span class="hljs-literal">true</span>,
       <span class="hljs-attr">hideEmptyFooter</span>: <span class="hljs-literal">true</span>,
       <span class="hljs-attr">noDataIcon</span>: <span class="hljs-string">"fa-database-search"</span>,
       <span class="hljs-attr">hideDeletedRows</span>: <span class="hljs-literal">true</span>,
       <span class="hljs-attr">pagination</span>: {
        <span class="hljs-attr">showRange</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">showPageLinks</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">maxLinks</span>: <span class="hljs-number">0</span>,
        <span class="hljs-attr">firstAndLastButtons</span>: <span class="hljs-literal">false</span>
      }
}

 <span class="hljs-keyword">return</span> options;
}
</code></pre>
<p>The code above should be added to the JavaScript Initialization Function, which is located under the Advanced section in region attributes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702024976867/6ceddc22-8ee0-4c78-8bff-420b0401dfac.png" alt="Interactive Grid, JavaScript Initialization Function" class="image--center mx-auto" /></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>I hope you find these options useful. They will be integrated into the Component Designer tool. Until then, feel free to write code manually. ;)</p>
<p>Check out the <a target="_blank" href="https://apex.oracle.com/pls/apex/r/rittmanmead/apex-component-designer/components?session=114804355602688">Component Designer</a> tool, there are already components and their options, that might be useful in your development.</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX: Popup LOV - Additional Outputs]]></title><description><![CDATA[Popup LOV is a very common APEX item type, used to cover more complex features that are not available in the Select List type, allowing us to search, and display multiple columns, which might be very helpful to decide which column you want to pick. B...]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-popup-lov-additional-outputs</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-popup-lov-additional-outputs</guid><category><![CDATA[#oracle-apex]]></category><category><![CDATA[orclapex]]></category><category><![CDATA[Oracle]]></category><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Mon, 20 Nov 2023 10:35:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1700475045967/cb20114f-b337-444d-a785-fdb537ecc1ad.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Popup LOV is a very common APEX item type, used to cover more complex features that are not available in the Select List type, allowing us to search, and display multiple columns, which might be very helpful to decide which column you want to pick. But, Popoup has also the ability to return additional columns to items on the page.</p>
<p>In this blog post, I will cover the Popup LOV feature called Additional Outputs, which is I believe not well known. This simple functionality might be very useful in your development, whenever you have items in a form that should have the same value as Additional Columns of the Popup LOV.</p>
<h3 id="heading-list-of-values">List of Values</h3>
<p>Let's quickly go through defining a list of values. List of Values (LOV) has a display and returns columns, standardly named as <code>d</code> for display value and <code>r</code> for return value. On the List of Values page under Shared Components you can define LOV, just provide the name, and follow the next steps. Example of a very simple LOV query, displaying column <code>name</code> and retrieving the value of <code>id</code> column.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">select</span> <span class="hljs-keyword">name</span> <span class="hljs-keyword">as</span> d, <span class="hljs-keyword">id</span> <span class="hljs-keyword">as</span> r
<span class="hljs-keyword">from</span> demo_restaurants;
</code></pre>
<p>I am selecting two columns, <code>d</code> as a display value and <code>r</code> as the value that will be returned by the item.</p>
<p>The next step is to map columns.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700477901876/aa5e1ba7-b8f3-4ebe-9dde-46b158edc5d5.png" alt class="image--center mx-auto" /></p>
<p>Now, LOV is ready to be used across your app. You can simply use it just pick it up from the Shared Components LOV.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700480353270/a71903ce-74e7-430a-a219-cae288241909.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-additional-columns">Additional Columns</h3>
<p>To fully leverage the Additional Outputs functionality, you need to define Additional Columns. This is particularly useful when a single display column may not uniquely identify a record, such as when dealing with the same restaurant name in different locations.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700470032895/681f637e-f1a5-4c1e-8d69-7287a000e867.png" alt class="image--center mx-auto" /></p>
<p>You can define display columns, and choose which columns are visible and searchable, you can set the display order etc.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Note: To be able to select more columns expand your LOV query by adding columns, you want to use as Additional Columns.</div>
</div>

<h3 id="heading-additional-outputs"><strong>Additional Outputs</strong></h3>
<p>Imagine you are working on a restaurant app, where you need to prefill fields such as name, address and city… that you already have in the database, so additional outputs can help you with that.</p>
<p>Once you have additional columns set, you can move to your page with the Popup LOV item and define Additional Outputs.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700470071261/a267daa1-8cfe-4880-995a-e77f4257ad51.png" alt class="image--center mx-auto" /></p>
<p>So it is important to map your columns, which are defined in LOV with page items. Example: COL1:P1_ITEM1,COL2:P1_ITEM2. If the columns and items are mapped correctly, no additional setting is needed.</p>
<p>Now, is the time to test if items are set correctly after we choose a value in Popup.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700470164742/8e39ade9-db3d-4a91-9fa0-7e71b692a9be.gif" alt class="image--center mx-auto" /></p>
<p>Additional Outputs feature is available in the Interactive Grid Popup LOV column as well.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Note: For the Interactive Grid columns you need to define a Static ID, and then use that in the Additional Outputs attribute.</div>
</div>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700479557688/b00325bc-ea4d-42d6-9c9a-8fa771884194.png" alt class="image--center mx-auto" /></p>
<p>Set the Additional Outputs attribute using the column Static IDs. For instance, <code>ADDRESS1:ADDRESS_IG,CITY:CITY_IG,STATE:STATE_IG,ZIP_CODE:ZIP_CODE_IG</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700479446081/063c6309-6f37-4a37-940a-35f6ca78d7b7.gif" alt class="image--center mx-auto" /></p>
<h3 id="heading-in-conclusion">In Conclusion</h3>
<p>This simple Popup LOV functionality might be very useful whenever you need to set some items from your additional columns. Doesn't matter if it is a page item or an Interactive Grid column. Simple, easy and super useful 🙂</p>
]]></content:encoded></item><item><title><![CDATA[Oracle APEX - UT: Responsive Classes]]></title><description><![CDATA[In this blog post, we will explore the Responsive Classes of Universal Theme, marking the beginning of the UT series. These helper classes are available from Universal Theme 1.2, they are designed to help you to improve the responsive experience in y...]]></description><link>https://petarsimic.hashnode.dev/oracle-apex-ut-responsive-classes</link><guid isPermaLink="true">https://petarsimic.hashnode.dev/oracle-apex-ut-responsive-classes</guid><category><![CDATA[Responsive Web Design]]></category><category><![CDATA[Oracle]]></category><category><![CDATA[orclapex]]></category><category><![CDATA[universal theme]]></category><dc:creator><![CDATA[Petar Simic]]></dc:creator><pubDate>Sun, 24 Sep 2023 12:49:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/EhTcC9sYXsw/upload/3a44f3218f91408de310c598fd4301d7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this blog post, we will explore the Responsive Classes of Universal Theme, marking the beginning of the UT series. These helper classes are available from Universal Theme 1.2, they are designed to help you to improve the responsive experience in your applications.</p>
<h3 id="heading-grid-layout">Grid Layout</h3>
<p>Grid Layout is a system of 12 columns used to arrange APEX components on the screen. Understanding the system will help you understand the responsive classes and their behaviour.</p>
<p><img src="https://www.rittmanmead.com/blog/content/images/2023/09/Screenshot-2023-09-20-at-12.34.45.png" alt="Layout system" /></p>
<p>Based on the screenshot above we can conclude, that we have a parent region with a span of 12 columns, with 12 regions with a span of 1 column, and 1 region with a span of 12 again, etc. so you can see that every region has assigned span, and the same region can assign the span to child components, which is additional 12 columns. On the smaller screens region are splited which makes them responsive.</p>
<h3 id="heading-responsive-classes">Responsive Classes</h3>
<p>Let's say you have three chart regions in one row, all of them have a span of 4 columns (image below).</p>
<p><img src="https://www.rittmanmead.com/blog/content/images/2023/09/Screenshot-2023-09-20-at-12.59.25.png" alt /></p>
<p>When you are on the phone they are splitted one below another which is great. But the problem comes when you are on a bit bigger screen, such as a tablet, they might be not splitted and make the user experience very bad.</p>
<p>Below is the same charts but, in the responsive mode, so you can see the behaviour on the different screen size.</p>
<p><img src="https://www.rittmanmead.com/blog/content/images/2023/09/charts_without_ut_classes.gif" alt /></p>
<p>So, as you can notice charts are not splitted and not user-friendly. This is the case when we need help from responsive classes, to get full control on spitting the regions to a new row.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td>All</td><td>XX Small</td><td>X Small</td><td>Small</td><td>Medium</td><td>Large</td><td>X Large</td><td>XX Large</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Range</strong></td><td>All</td><td>479px and below</td><td>480px to 639px</td><td>640px to 767px</td><td>768px to 991px</td><td>992px to 1199px</td><td>1200px to 1399px</td><td>1400px and above</td></tr>
<tr>
<td><strong>CSS Class Prefix</strong></td><td>.col-</td><td>.col-xxs-</td><td>.col-xs-</td><td>.col-sm-</td><td>.col-md-</td><td>.col-lg-</td><td>.col-xl-</td><td>.col-xxl-</td></tr>
<tr>
<td><strong>Number of Columns</strong></td><td>12</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr>
<td><strong>Gutter</strong></td><td>1rem (0.5rem each side)</td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
</tbody>
</table>
</div><p>The table above explains the range and provide class prefix that you can use, so, for instance, to split regions on smaller screens you can use this combination of classes - <strong>col-xxs-12 col-xs-12 col-sm-12 col-md-6 col-lg-4</strong> These classes will split regions to new rows on smaller screens. On the medium screen, the region will be half of the screen, and on a big one, it will be a third of the screen. 12, 6, and 4 are the numbers of columns(span in the Grid Layout) you want to have on that component when the screen is in a certain range.</p>
<p>Result after adding the column classes to charts. Charts are splitted one below another.</p>
<p><img src="https://www.rittmanmead.com/blog/content/images/2023/09/chart_with_ut_classes.gif" alt /></p>
<p>A place to add the classes is the region &gt; Column CSS Classes as shown in the image below.</p>
<p><img src="https://www.rittmanmead.com/blog/content/images/2023/09/Screenshot-2023-09-21-at-13.45.04.png" alt /></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Incorporating responsive classes into your design improves the user experience, but also eliminates the need for custom coding, which potentially can produce problems on application/theme upgrades.</p>
]]></content:encoded></item></channel></rss>