# Calling PL/SQL from JavaScript in Oracle APEX with AJAX

> **Updated from 2023**
> 
> This article is an updated English version of a post I originally published in Hungarian in 2023. [**Read the original Hungarian version →**](/plsql-futtatasa-a-hatterben)

Oracle APEX does an excellent job of supporting declarative application development.

In Page Designer, we can build a page using components, configure their properties, add a few processes or validations, and very quickly have a working business application.

But sometimes we want to execute server-side logic without submitting and rebuilding the whole page.

This is where AJAX becomes useful.

In this example, I will show how to call a PL/SQL process from JavaScript using `apex.server.process`, pass a value to the server, update data in the database, and refresh only the affected region.

## The example

Let's use a very simple Classic Report showing employees and their salaries.

When the user clicks a salary value, we want to:

1.  identify the employee,
    
2.  call a server-side PL/SQL process,
    
3.  double the employee's salary,
    
4.  return control to the browser,
    
5.  refresh the report.
    

There is no full page submit.

## 1\. Make the report value clickable

Assume our Classic Report query returns:

*   `EMPLOYEE_ID`
    
*   `SALARY`
    

Instead of using an inline JavaScript handler, we can give the link a CSS class and store the employee ID in a data attribute.

In the **HTML Expression** of the Salary column:

```html
<a href="#" class="js-salary" data-employee-id="#EMPLOYEE_ID#">#SALARY#</a>
```

The report now renders the salary as a clickable value.

The `data-employee-id` attribute contains the ID of the employee whose salary we want to update.

## 2\. Create a Dynamic Action

Create a Dynamic Action with:

*   **Event:** Click
    
*   **Selection Type:** jQuery Selector
    
*   **jQuery Selector:** `.js-salary`
    

Because the report will later be refreshed, configure the event so that it also works for dynamically refreshed report rows.

For the True Action, choose **Execute JavaScript Code**.

Use:

```javascript
const employeeId = this.triggeringElement.dataset.employeeId;

console.log("Employee ID:", employeeId);

apex.server.process(
    "PROC_SALARY",
    {
        x01: employeeId
    },
    {
        dataType: "text",

        success: function (pData) {
            console.log("Server response:", pData);
            apex.region("myREPORT").refresh();
        },

        error: function (jqXHR, textStatus, errorThrown) {
            apex.debug.error(
                "PROC_SALARY failed",
                textStatus,
                errorThrown
            );

            apex.message.alert("The salary update failed.");
        }
    }
);
```

The important part is:

```javascript
apex.server.process("PROC_SALARY", ...)
```

This calls an APEX Ajax Callback named `PROC_SALARY`.

We pass the employee ID using:

```javascript
x01: employeeId
```

On the server side, APEX exposes this value through:

```plsql
apex_application.g_x01
```

## 3\. Create the PL/SQL Ajax Callback

Create an **Ajax Callback** process named:

```text
PROC_SALARY
```

The PL/SQL code can look like this:

```plsql
begin
    update oehr_employees
       set salary = salary * 2
     where employee_id = to_number(apex_application.g_x01);

    commit;

    htp.p('ok');
exception
    when others then
        rollback;
        apex_debug.error('PROC_SALARY failed: %s', sqlerrm);
        raise;
end;
```

The value passed from JavaScript in `x01` is available through:

```plsql
apex_application.g_x01
```

We use it to identify the employee whose salary needs to be updated.

The callback sends a simple text response back to JavaScript:

```plsql
htp.p('ok');
```

Because the JavaScript call specifies:

```javascript
dataType: "text"
```

the returned value is available in the `success` function as `pData`.

## 4\. Refresh only the report

If the server-side process completes successfully, we execute:

```javascript
apex.region("myREPORT").refresh();
```

For this to work, set the Classic Report's **Static ID** to:

```text
myREPORT
```

Only the report is refreshed.

The rest of the page remains unchanged.

The complete flow is therefore:

```text
User clicks Salary
        ↓
Dynamic Action
        ↓
apex.server.process
        ↓
PROC_SALARY Ajax Callback
        ↓
UPDATE in Oracle Database
        ↓
Response returned to JavaScript
        ↓
Classic Report refresh
```

## Why use AJAX?

The main advantage is that we do not need to submit and reload the entire page just to execute a small server-side operation.

This can provide a smoother user experience for operations such as:

*   changing a value,
    
*   executing a small PL/SQL operation,
    
*   validating data,
    
*   retrieving server-side information,
    
*   refreshing part of a page,
    
*   triggering business logic from a user action.
    

It also allows us to combine APEX's declarative development model with JavaScript when we need more control over the interaction.

## What changed since the original 2023 version?

The core idea of the original article remains valid.

`apex.server.process` is still a useful way to call server-side APEX processes from JavaScript.

However, I would implement the client-side part differently today.

My original example used JavaScript directly inside the report link. In modern APEX applications, I prefer separating markup from behavior and using Dynamic Actions or dedicated JavaScript code instead.

This makes the application easier to understand, maintain and change later.

Error handling is another area worth making explicit.

A real application should not assume that every AJAX request succeeds. Both the client and server side should handle unexpected errors appropriately.

## AJAX is not the same as background processing

There is also an important distinction.

Although the PL/SQL process executes without a full page submit, this is still a request-response operation.

The browser sends the AJAX request and waits for the server-side process to finish.

For short operations, this is exactly what we want.

For genuinely long-running tasks — imports, large calculations, integrations or batch processing — a real background execution mechanism is usually more appropriate.

That may involve APEX background processing capabilities or database mechanisms such as `DBMS_SCHEDULER`.

So the question is not simply:

**How can I run PL/SQL in the background?**

A better question is:

**Does the user need to wait for the result, or should the work continue independently of the browser request?**

That distinction becomes increasingly important as APEX applications grow from simple pages into larger enterprise systems.

## Conclusion

One of the strengths of Oracle APEX is that we can start with declarative development and add lower-level control only where we actually need it.

`apex.server.process` provides a simple bridge between browser-side JavaScript and server-side PL/SQL.

For small interactive operations, it allows us to:

**JavaScript → PL/SQL → Oracle Database → refresh only what changed**

without submitting the whole page.

It is a small technique, but one I have used repeatedly in real APEX applications.
