Sunday, May 31, 2026

Enhance Page Process Security in Oracle APEX

 Secured application is highly recommended in every business. How we can make our application secure? There are many ways to secure an application. Today I'm going to discuss a way to secure page process. I assume, you have a complete functionsl page in your application. I choose page 47 in my APEX application to illustrate the process. You can choose your suitable page to implement this process. For visual assistance, you can follow this tutorial.

Now I'm going to discuss this process step by step-

STEP 1: Select page and open "Header Text" code Editor. Paste the below code here-

<div id="pageSpinnerOverlay">

<div class="spinner"></div>

<div class="msg"></div>

</div>

STEP 2: Open CSS > Inline code editor and paste the below css here-

/*Display the overlay block*/

#pageSpinnerOverlay {

display: none;

position: fixed;

top: 0;

left: 0;

width: 100%;

height: 100%;

background-color: rgba(0, 0, 0, 0.4);

z-index: 9999;

}

#pageSpinnerOverlay .spinner {

position: absolute;

top: 50%;

left: 50%;

transform: translate(-50%, -50%);

border: 8px solid #f3f3f3;

border-radius: 50%;

width: 60px;

height: 60px;

animation: spin 1s linear infinite;

border-top: 8px solid #3498db;

}

@keyframes spin {

0% {

transform: translate(-50%, -50%) rotate(0deg);

}

100% {

transform: translate(-50%, -50%) rotate(360deg);

}

}

#pageSpinnerOverlay .msg {

position: absolute;

padding: 8px;

font-size: 12px;

font-family: "Times New Roman";

font-style: italic;

text-align: center;

color: #000;

letter-spacing: 3px;

top: 58%;

left: 50%;

transform: translate(-50%, -55%);

}

STEP 3: Open JavaScript > "Function and Global Variable Declaration" code editor and paste the below code here-

function showSpinner(msg) {

let msgContainer = document.getElementsByClassName('msg');

msgContainer[0].innerHTML = msg;


$('#pageSpinnerOverlay').css('display', 'flex');

$('#pageSpinnerOverlay').css('flex-direction', 'column');


$('#pageSpinnerOverlay').show();

};

function hideSpinner() {

$('#pageSpinnerOverlay').hide();

};

STEP 4: Create Ajax Callback Process to perform your DML operation. Suppose, you want to increase employee salary by 10%. So, create a new Ajax Callback process and set it properties like-

Name: UPDATE_SALARY

PL/SQL Code: UPDATE employees

SET salary = salary + (Salary * .1);

STEP 5: Go to "Navigation" tab and select page. Open JavaScript > "Function and Global Variable Declaration" code editor. Paste the below code here-

function updateSalary() {

apex.message.clearErrors();

showSpinner('Data is uder processing. Please wait...');

apex.server.process(

'UPDATE_SALARY'

, {}

, {

dataType: 'text',

success: function() {

apex.message.showPageSucess('Update Salary successful');

}

}

);

hideSpinner();

}

Note: You can't noticed anything using this simple process because the process finished within a nano-second. If your process took a little bit longer time then you can notice its effect.

STEP 6: Select the button which is responsible to perform DML operation. Change it properties like-

Behaviour:

Action: Defined by Dynamic Action

STEP 7: Create a dynamic action under this button and set the action name as your choice. Select true action and set it properties like-

Action: Execute JavaScript Code

Code: updateSalary();

Save your page and run. Hope, you can cofigure your page successfully. This process will secure your page from intentionally click/execute another process when a process is already running. This process force the user to wait untill the executed process not finished. Let's enjoy.

Oracle APEX- Implement Drag & Drop Tree Structure

Oracle APEX tree region or page is not provided the drag and drop features by default. When you think to implement such kind of features, you need to think from out of the box. To add this features you need to build your tree structure from scratch. Using javascript library named "jstree", I have implemented "drag & Drag" features in my custom tree structure. Let me show the whole process step by step. You can find a visual assistance from here.


STEP 1: Create a blank page and named it "Drag & Drop Tree".

STEP 2: Select page and open JavaScript "File URLs" code editor. Copy the link from "cdnjs.com/libraries/jstree" and paste the below link here- https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.17/jstree.min.js (Step 2 or 3 any one is required).

STEP 3: (Optional) Copy the code from the above URL for offline support. Open nodepad and paste here. Save the file as jstree.js file. Go to APEX page and click on "Shared Component" icon. Click on "Static Application Files" and upload the jstree.js file. Copy the "Reference" link. Go back to APEX page and open JavaScript "File URLs" code editor. Paste the "Reference" link here.

STEP 4: Create a new region and set the below properties-

HTML Code : <div id='emp-tree'></div>

STEP 5: Create a button under the above region and set the properties like below-

Name: BTN_EXPAND_ALL

Label: Expand All

Region: Emp Tree

Slot: Edit

Button Template: Icon

Hot: Yes (Switch on)

Template Options:

Size: Small

Icon: fa-expand

STEP 6: Create another button and set the properties like below-

Name: BTN_COLLAPSE_ALL

Label: Collapse All

Region: Emp Tree

Slot: Edit

Button Template: Icon

Hot: Yes (Switch on)

Template Options:

Size: Small

Type: Danger

Spacing Left: Small

Icon: fa-compress

STEP 7: Click on the process icon from the navigation pane. Right click on "Ajax Callback" and Select "Create Process". Set it properties like-

Name: GET_DATA

PL/SQL Code: apex_json.open_array;

FOR i IN (

SELECT employee_id AS emp_id 

, NVL(manager_id,0) AS parent_id

, first_name||' '||last_name AS emp_name

FROM employees1

ORDER BY employee_id

) LOOP

apex_json.open_object;

apex_json.write('EMP_ID', i.emp_id);

apex_json.write('PARENT', i.parent_id);

apex_json.write('NAME', i.emp_name);

apex_json.close_object;

END LOOP;

apex_json.close_all;

STEP 8: Click on the "Navigator" icon and select page. Open the "Execute when Page Loads" code editor and paste the below code-

function buildTree(items) {

const map = {};

const root = [];


//Assign temporary unique key for tree

items.forEach((item, index) => {

map[index] = {...item, children:[], _uniqueId: index}

});


//Build Hierarchy

items.forEach((item, index) => {

if(item.PARENT === 0) {

root.push(map[index]);

} else {

//Find matching parent by EMPLOYEE ID

const parent = items.find(p=> p.EMP_ID === item.PARENT);

if(parent) {

const parentIndex = items.indexOf(parent);

map[parentIndex].children.push(map[index]);

}

}

});

return root;

}

//Convert to tree node recursively

function convert2tree(node) {

return {

text: node.NAME,

id: 'node_'+node.EMP_ID,

emp_id: node.emp_id,

parent_id: node.PARENT,

children: node.children.map(convert2tree)

}

}


apex.server.process(

'GET_DATA'

, {}

, {

dataType: 'json',

success: function(pData) {

try {

const treeData = buildTree(pData);


$('#emp-tree').jstree({

core: {

data: treeData.map(convert2tree),

check_callback: true

},

plugins:['dnd']

})

} catch (err) {

console.log('Tree build error = '+err);

}

},

error: function(err) {

console.log('AJAX error = '+ err);

}

}

)


$('#emp-tree').on('move_node.jstree', function(e, data) {

const nodeEl = $('#'+ data.node.id +'_anchor');

nodeEl.addClass('drag-highlight');

})

STEP 9: Select the "BTN_EXPAND_ALL" button and create a dynamic action here. Set it properties like-

Name: Expand Tree

Event: Click

Button: BTN_EXPAND_ALL

STEP 10: Select the newly create true action and set it propertieslike below-

Action: "Execute JavaScript Code"

Code: $('#emp-tree').jstree('open_all');

STEP 11: Select the "BTN_COLLAPSE_ALL_ALL" button and create a dynamic action here. Set it properties like-

Name: Collapse Tree

Event: Click

Button: BTN_COLLAPSE_ALL

STEP 12: Select the newly create true action and set it propertieslike below-

Action: "Execute JavaScript Code"

Code: $('#emp-tree').jstree('close_all');

STEP 13: Select page and open CSS > File URLs Code editor. Paste the link here- https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.17/themes/default/style.min.js (Step 13 or 14 any one is required).

STEP 14: Open another new tab and paste the link into the url- cdnjs.com/libraries/jstree. Copy the link (https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.17/themes/default/style.min.js) from here and paste it to the url. Copy the css code from here and open a blank nodepad and paste the css code here. Save it as style.css. Go to the APEX page and click on the "Shared Components" icon. Select "Static Application Files" and upload the style.css file. Copy the "Reference" link. Return to the page and open CSS > File URLs code editor. Paste the "Reference" link here.


That's it for today. Next episode, I'll show the rest of that series (Implement DML operation). 

Thursday, May 21, 2026

Dynamic Content to PDF file generate in Oracle APEX

 In oracle APEX, it is not easy to generate pdf file from a dymic content specially from APEX 24.2 or earlier version. There is no built in process to generate pdf file from dynamic content. That's why some times we need to depend on thirds party tools to accomplish our jobs. 

I considered that you have already a dynamic content in your application's page. I try to resolve this critical business logic with the help of no third party tools, just only using 2 javascripts library. This process is discuss below step by step. For visual guidance, you follow the process from here (html2pdf).

STEP-1: Copy the jsPdf library file link from the Code Depository Network (CDN). Add the link to the page level javascripts file URLs.


STEP-2: Create javascript function to convert html document to PDF file. Click on the Function and Global Variable Declaration icon to open the code editor. Paste the below code here- 

function html2pdf(htmlContentId, callback) {

    let htmlContent = document.getElementById(htmlContentId);


    const { jsPDF } = window.jspdf;

    const doc = new jsPDF({

        orientation: 'p',

        unit: 'mm',

        format: 'a4'

    });


    doc.html(htmlContent, {

        x: 15,

        y: 15,

        width: 310,

        windowWidth: 1094,

        html2canvas: {

            scale: 0.16,

            useCORS: true,

            logging: false

        },

        callback: function(doc){

            const arrayBuffer = doc.output('arraybuffer');

            callback(arrayBuffer);

        }

    })

}

function pdfUsage(htmlContentId, state) {

    html2pdf(htmlContentId, function(arrayBuffer){

        const blob = new Blob([arrayBuffer], {type:'application/pdf'});

        const url = URL.createObjectURL(blob);


        const link = document.createElement('a');

        link.href = url;


        if (state === 'Download') {

            link.download = 'Application.pdf';

            document.body.appendChild(link);

            link.click();

        } else if (state === 'Preview') {

            link.download = 'Application.pdf';

            window.open(url, '_blank');

        } else if (state === 'Mail') {

            apex.message.clearErrors();


            const reader = new FileReader();

            reader.onloadend = function() {

                const base64data = reader.result;

                const clob = base64data.split(',')[1];

                

                apex.server.process(

                    'SENT_PDF_AS_ATTACHMENT'

                    , {

                        p_clob_01: clob

                    }

                    , {

                        dataType: 'text',

                        success: function() {

                            apex.message.showPageSuccess('Mail sent successfully with attachemnt');

                        }

                    }

                )

           }

           reader.readAsDataURL(blob);

        }

    })

}



STEP-3: Create an AJAX Callback process to send the mail. Click on the "Process" icon from the left side navigation pane. Right click on the "Ajax Process" and select "Create Process". Set it name as "SENT_PDF_AS_ATTACHMENT" and open the "PL/SQL Code" editor. Paste the below code here-

DECLARE

    l_file  BLOB;

    l_mail_id   NUMBER;

BEGIN

    l_file  := apex_web_service.clobbase642blob(

        p_clob  => apex_application.g_clob_01

    );


    l_mail_id   := APEX_MAIL.SEND(

                        p_to           => 'rummanalam@yahoo.com',

                        p_from         => 'rummancnsl@gmail.com',

                        p_body         => 'This is a test mail for html 2 pdf converted report attachment. Please ignore it.',

                        p_subj         => 'Html2pdf Report Converted & Sent as Attachment'

                );

    APEX_MAIL.ADD_ATTACHMENT(

            p_mail_id    => l_mail_id,

            p_attachment => l_file,

            p_filename   => 'Html2pdf',

            p_mime_type  => 'application/pdf');

END;



Now Save your page and run. Hope, it will perfectly sent an email perfectly. Keep it mind that, this tutorial is for only showing to convertion of Html to Pdf  nothing else. If you stuck on sending email then you need to configure your email first. You can find solutions to configure email from both Youtube and  here.

Let's Enjoy! Happy coding.

Saturday, May 16, 2026

Build a Dynamic Hierarchical Tree Report with multiple columns in Oracle APEX

 We have to implement many requirements in our software development life cycle. This tree report is one of them requirements. The main requirements is need tree report with multiple columns to represent data properly and perfectly. By default in Oracle APEX, we can't develop multi-columns tree report. That's why, this is my efforts to overcome the limitation of default tree of APEX. So, lets start the discussion step by step. For visual assistance, you can follow the process from here.

STEP-1: Fisrt create a blank page. Then crate a region. Set it's below properties like

        Name:     Custom Tree Report

        type:        'Dynamic Content'



        PL/SQL Code

                                    DECLARE

    l_clob  CLOB;

BEGIN

    l_clob  := '<table class="a-IRR-table">

                    <tr>

                        <td class="a-IRR-header u-tC">Name</td>

                        <td class="a-IRR-header u-tC">Emp No.</td>

                        <td class="a-IRR-header u-tC">Manager ID</td>

                        <td class="a-IRR-header u-tC">Direct Subordinates</td>

                    </tr>

                    <tbody id="myTableBody">';

    

    FOR i IN (

        SELECT empno

            , ename

            , mgr AS manager_id

            , (SELECT COUNT(*)

                FROM emp 

                WHERE mgr = e.empno

            ) AS subordinates

            , SUBSTR(rec_level, INSTR(rec_level, 'L', -1)+1) AS rec_level

        FROM emp e 

        WHERE rec_level = 'LEVEL1'

    ) LOOP

        l_clob  := l_clob||

                    '<tr id="tr-'||i.empno||'">

                        <td class="u-tL"><span id="'||i.empno||'" style="padding-left:'||i.rec_level * 20||'px;" class="expand-collapse fa fa-plus-square-o" onclick="showDependent(this)"></span>'||i.ename||'</td>

                        <td class="u-tC">'||i.empno||'</td>

                        <td class="u-tC">'||i.manager_id||'</td>

                        <td class="u-tC">'||i.subordinates||'</td>

                    </tr>'  ;

    END LOOP;


    l_clob  := l_clob||'</tbody>

                </table>';

    RETURN l_clob;

END;

[Note: Use you own data table and you must need to add a column on your table/view named "rec_level" and data will be like 'level1', level2' etc.]


STEP-2: Create a AJAX Callback process to prepare child records of the parent. Click on the process tab icon from the left navigation pane. Right click on the 'Ajax Callbacks' and then select 'Create Process'.


Set the below properties as like-

Name:     ADD_DEPENDENT

Type:     Execute Code

PL/SQL Code:

        apex_json.open_array;

FOR i IN (

    SELECT empno

        , ename

        , mgr AS manager_id

        , (SELECT COUNT(*)

            FROM emp 

            WHERE mgr = e.empno

        ) AS subordinates

        , SUBSTR(rec_level, INSTR(rec_level, 'L', -1)+1) AS rec_level

    FROM emp e 

    WHERE mgr = apex_application.g_x01

) LOOP

    apex_json.open_object;

    apex_json.write('EMPNO', i.empno);

    apex_json.write('ENAME', i.ename);

    apex_json.write('SUBORDINATE', i.subordinates);

    apex_json.write('MGR', i.manager_id);

    apex_json.write('LEVEL', i.rec_level);

    apex_json.close_object;

END LOOP;

apex_json.close_all;


STEP-3: Go back to the navigator tab and select the page. Now go to the page properties and scroll down to "Function and Global Variable Declaration". Open the code editor and paste the below code here-

function showDependent(empId) {
    let eId = empId.id, i;

    if ($('#'+eId).hasClass('fa-plus-square-o')) {
        $('#'+eId).removeClass('fa-plus-square-o');
        $('#'+eId).addClass('fa-minus-square-o');
        
        apex.server.process(
            'ADD_DEPENDENT'
            , {
                x01: eId
            }
            , {
                dataType: 'json',
                success: function(pData) {
                    let targetRow = document.getElementById('tr-'+eId);

                    for (i = 0; i < pData.length; i++) {
                        let tr = document.createElement('tr');
                        tr.setAttribute('id', 'tr-'+pData[i].EMPNO);
                        tr.setAttribute('data-parent', eId);

                        // create reprot column one by one
                        let eName = document.createElement('td');
                        eName.classList.add('u-tL');
                        if (parseInt(pData[i].SUBORDINATE) > 0) {
                            eName.innerHTML = '<span id="'+pData[i].EMPNO+'" style="padding-left:'+(pData[i].LEVEL*20)+'px;" class="expand-collapse fa fa-plus-square-o" onclick="showDependent(this)"></span>'+pData[i].ENAME;  
                        } else {
                            eName.innerHTML = '<span id="'+pData[i].EMPNO+'" style="padding-left:'+(pData[i].LEVEL*20)+'px;" class="expand-collapse fa fa-plus-square-0" onclick=""></span>'+pData[i].ENAME;   
                        }

                        //FOR empno column
                        let empNo = document.createElement('td');
                        empNo.classList.add('u-tC');
                        empNo.innerHTML = pData[i].EMPNO;

                        //For manager Id column
                        let mgr = document.createElement('td');
                        mgr.classList.add('u-tC');
                        mgr.innerHTML = pData[i].MGR;

                        //FOR DIRECT SUBRODINATES column
                        let dirSub = document.createElement('td');
                        dirSub.classList.add('u-tC');
                        dirSub.innerHTML = (parseInt(pData[i].SUBORDINATE) > 0)?pData[i].SUBORDINATE:'';
                    
                        //APPEND these column to the TR
                        tr.append(eName, empNo, mgr, dirSub);

                        //Add the row after the appropriate parent record
                        targetRow.after(tr);
                    }
                }
            }
        )
    } else {
        hideDependent(eId); //later will be declare
        $('#'+eId).removeClass('fa-minus-square-o');
        $('#'+eId).addClass('fa-plus-square-o');
    }
}

function hideDependent(eId) {
    let childRows = document.querySelectorAll("[data-parent='"+eId+"']");

    childRows.forEach(function(row) {
        let childId = row.id.replace('tr-',""); // Get the numeric emp number.
        hideDependent(childId); // recursively remove the child row.
        row.remove(); // Finally remove the childs
    });
}

That's it. Now save and run. Hope, you have done a great job. let's enjoy the fun


Tuesday, October 7, 2025

How to track geo-location from Oracle APEX

In today’s data-driven world, location awareness has become a cornerstone of modern web and mobile applications. From logistics and field service management to attendance systems and customer engagement, knowing where an event or action occurs adds incredible value to your data insights. 

Oracle APEX, with its powerful integration capabilities and low-code flexibility, allows developers to seamlessly capture and utilize geo-location data directly within their applications—without relying on external tools or complex APIs. By combining HTML5 geolocation features with PL/SQL and APEX components, you can easily track a user’s current position, display it on a map, or even store it. You can find a visual assistance from here.



So, let's walk through the process step by step-


STEP- 1:

Create a blank page using the page creation wizard. Set the page name as "Location Capture". Under the "Navigation" section, set "No" for "Use Breadcrumb" option. Left other properties as it is. Click on "Create Page" button. A blank page will be create and redirect to the new page.


STEP- 2:

Create a new region and set its properties as like below-

        Name:             Location Capture

        Column Span: 3


STEP- 3:

Create 2 page items like P4_LATITUDE and P4_LONGITUDE under the "Location Capture" region which was created in STEP 2. Create a button and set it's properties as like below-

        

        Name                    : BTN_LOCATION_CAPTURE

        Label                    Capture Location 

        Position                : Close

        Hot                       : Yes (Toggle On)

        Template Options:

                Size              : Small


Create another button and set it properties as like below-

        Name                    : BTN_LOCATION_REFRESH

        Label                    : Refresh Location 

        Position                : Create

        Hot                       : Yes (Toggle On)

        Template Options:

                Size              : Small

                

STEP- 4:

Create a dynamic action under the "BTN_LOCATION_CAPTURE" button which is created earlier. Set it's name like "Capture physical location". Select the true action and set it's properties like-

    

        Action      : Execute JavaScript Code

        Code        : captureLocation()


STEP- 5:

Select the page (At the top of the left side pane) and navigate to the "Function and Global Variables Declaration" properties under the JavaScript section. Open the code editor and paste the below code here-

        function captureLocation() {

            if ("geolocation" in navigator) {

                // Prompt user for permission to access their location

                navigator.geolocation.getCurrentPosition(

                    // Success callback function

                    (position) => {

                        // Get the user's latitude and longitude coordinates

                        const lat = position.coords.latitude;

                        const lng = position.coords.longitude;

                        apex.item("P4_LATITUDE").setValue(lat);

                        apex.item("P4_LONGITUDE").setValue(lng);        


                        // Do something with the location data, e.g. display on a map

                        console.log('Latitude: ${lat}, longitude: ${lng}');

                    },

                    // Error callback function

                    (error) => {

                        // Handle errors, e.g. user denied location sharing permissions

                        console.error("Error getting user location:", error);

                    }

               );

            } else {

                // Geolocation is not supported by the browser

                console.error("Geolocation is not supported by this browser.");

            };

        }


STEP- 6:

Add another region in this page and set it's properties like below-

        Name        : Map

        Type          : Map

        Source > Type: SQL Query

        SQL Query:

                                SELECT TO_NUMBER(:P4_LATITUDE) AS latitude

                                    , TO_NUMBER(:P4_LONGITUDE) AS longitude

                                FROM dual


        Page Items to Submit    : P4_LATITUDE, P4_LONGITUDE

        Start New Row              : No (Toggle Off)

        Geometry Column Data Type: Latitude/Longitude

        Longitude Column         longitude

        Latitude Column            : latitude

        Static ID                         : location

        Point Objects                  :

                Style                       : Icon

                Icon Source            : Icon Class

                Icon CSS Classes   : fa fa-map-marker

        Fill Color                        : #161010


Select attribute tab immediate next to the region tab in the properties section and set the below properties-

        Background   : Custom

        Standard        : Oracle World Map

        Initial Position and Zoom:

                Type              : SQL Query

                SQL Query   SELECT TO_NUMBER(:P4_LATITUDE) AS latitude

                                            , TO_NUMBER(:P4_LONGITUDE) AS longitude

                                        FROM dual


        Geometry Column Data Type: Latitude/Longitude

        Inital Longitude Column         : longitude

        Inital Latitude Column            : latitude


STEP- 7:

Create a dynamic action under the "BTN_LOCATION_REFRESH" button which is created earlier. Set it's name like "Refresh location". Select the true action and set it's properties like-

    

        Action      : Execute JavaScript Code

        Code        : apex.region('location').refresh();


STEP- 8:

Create a page process under the before header sub section in the pre-rendering section. Set it's properties like-

        

        Name    : Clear Page

        Type      : Clear Session State


Save the page and run. That's all for today.

        

                            

Saturday, October 4, 2025

How to integrate camera with Oracle APEX

Modern business applications are no longer limited to static data entry—they are expected to interact seamlessly with the real world. Imagine capturing an image for identity verification, product tracking, field inspections, or real-time reporting—all directly within your Oracle APEX application.

The good news? You don’t need heavy integrations or third-party tools to achieve this. Oracle APEX provides the flexibility to integrate a device’s camera effortlessly, allowing users to capture and store images in just a few clicks. You can get a visual assistance from here.

In this blogpost, we’ll walk through how to bring camera functionality into Oracle APEX turning your application into a more intuitive, dynamic, and business-ready solution.

 STEP- 1: 

Create a blank page. Set it name as like "Camera Integration".


STEP- 2: 

Add a region. Set it's porperties as like-

        Name: Camera Integration

        Column: 3

        Column Span: 8


STEP- 3: 

Create 3 buttons under this region. Set it porperties like below-

    Button 1:

        Name: BTN_START_CAMERA

        Label: Start Camera

        Region: Camera Integration

        Slot: Edit

        Hot: Yes (Toggle On)

        Button Templete: Text with Icon

        Template Options:

                Size: Small

        Icon: fa-video-camera

    Button 2:

        Name: BTN_CAPTURE_IMAGE

        Label: Capture

        Region: Camera Integration

        Slot: Edit

        Hot: Yes (Toggle On)

        Button Templete: Text with Icon

        Template Options:

                Size: Small

        Icon: fa-camera

Button 3:

        Name: BTN_CLOSE_CAMERA

        Label: Close

        Region: Camera Integration

        Slot: Create

        Hot: Yes (Toggle On)

        Button Templete: Text with Icon

        Template Options:

                Size: Small

                Type: Danger

        Icon: fa-remove


STEP- 4: 

Create another region and set it's properties like below- 

        Name: Camera

        HTML Code: 

                                <div>

                                    <video id="video" width="200" height="140" autoplay></video>

                                </div>

        Template Options:

                Header: Hidden


STEP- 5:

Create another region to display the captured image. Set the region properties as like-

        Name: Captured Image

        HTML Code: 

                                <div>

                                        <canvas id="canvas" style="width:200px; height:140px"></canvas>

                                </div>

        Start New Row: No (Toggle Off)

        Template Options:

                Header: Hidden

STEP- 6:

Create JavaScript function to start camera, capture image and stop the camera. Select the page and open the "Function and Global Variable Declaration" code editor. Paste the below code here-

        function start() { 

var video = document.getElementById('video'), 

vendorUrl = window.URL || window.webkitURL; 

if (navigator.mediaDevices.getUserMedia) { 

navigator.mediaDevices.getUserMedia({ video: true }) 

.then(function (stream) { 

video.srcObject = stream; 

}).catch(function (error) { 

console.log("Something went wrong!"); 

}); 

}


function capture() {

var canvas = document.getElementById("canvas");

var video = document.querySelector("video");

var src;

canvas.width = video.videoWidth;

canvas.height = video.videoHeight;

canvas.getContext("2d").drawImage(video, 0, 0, video.videoWidth, video.videoHeight);


/** Code to merge image **/

/** For instance, if I want to merge a play image on center of existing image **/

const playImage = new Image();

   // playImage.src = "path to image asset";

playImage.onload = () => {

const startX = video.videoWidth / 2 - playImage.width / 2;

const startY = video.videoHeight / 2 - playImage.height / 2;

canvas.getContext("2d").drawImage(playImage, startX, startY, playImage.width, playImage.height);

canvas.toBlob() = (blob) => {

const img = new Image();

img.src = window.URL.createObjectUrl(blob);

};

};

const dataURL = canvas.toDataURL();    

const getBase64StringFromDataURL = (dataURL) => dataURL.replace('data:', '').replace(/^.+,/, '');

const base64 = getBase64StringFromDataURL(dataURL);


apex.server.process ( "INSERT_IMG", {

p_clob_01: base64

},{ dataType: 'text',

success: function( pData ) {

apex.message.showPageSuccess('Image Successfully Captured.');

apex.region('display-img').refresh();

}

} );

}

function stop() { 

var stream = video.srcObject; 

var tracks = stream.getTracks(); 

for (var i = 0; i < tracks.length; i++) { 

var track = tracks[i]; 

track.stop(); 

video.srcObject = null; 

}

Click OK button to close the editor.


STEP-7:

Call the start() function in "Execute When Page Loads". This will start your camera when the page load.


STEP- 8: 

Create a dynamic action Under the "BTN_START_CAMERA". Set it's name as "Start Camera". Change it true action from show to "Execute JavaScript Code". In code section call the start() function.


STEP- 9: 

Create another dynamic action Under the "BTN_CAPTURE_IMAGE". Set it's name as "Capture Image". Change it true action from show to "Execute JavaScript Code". In code section call the capture() function. After capturing the image, we need to stop the camera. So, we need to execute the stop() function also.



STEP- 10: 

Create another dynamic action Under the "BTN_CLOSE_CAMERA". Set it's name as "Stop Camera". Change it true action from show to "Execute JavaScript Code". In code section call the stop() function.


STEP- 11: 

Create an AJAX callback process the save the captured image into the database. Navigate to the process tab and select "AJAX Callback". Right click here and select "Create Process".


Select the newly create process and change it properties as like below-

        Name: INSERT_IMG

        PL/SQL Code:

                                DECLARE

                                l_img_id    NUMBER;

                                l_blob      BLOB;

                                BEGIN

                            SELECT NVL(MAX(img_id),0) + 1

                            INTO l_img_id

                            FROM image_capture;

                           l_blob := apex_web_service.clobbase642blob(

      p_clob    => apex_application.g_clob_01

          );

                            INSERT INTO image_capture(img_id, img)

                            VALUES(l_img_id, l_blob);

                            END ;

Click OK.


STEP-12:

Create another region to display the newly captured and saved image. Set the region properties as like below-

        Name: Display Image

        Type: Interactive Report

        SQL Query:

                            SELECT img_id, 

                        '<img width="80px" height="80px" src="'||apex_util.get_blob_file_src('P16_IMG', img_id)||'"/>' AS img

                            FROM image_capture 


        Column: 3

        Column Span: 8

        Static ID: display-img

STEP-13:

Select the "img" column under the interactive report and set the below properties-

        Escape Special Characters: No (Toggle Off)


Save and run the page. That's all. Integrating camera functionality into Oracle APEX is more than just a technical enhancement—it’s a strategic step toward creating smarter, user-friendly, and business-ready applications. From capturing employee IDs and customer documents to streamlining field inspections and product tracking, the possibilities are endless.

By leveraging APEX’s flexibility, you can deliver applications that not only simplify data collection but also enhance user experience through real-time interaction with the physical world. As digital transformation accelerates, this kind of seamless integration empowers organizations to stay ahead, making Oracle APEX a powerful platform for building truly modern applications.