Oracle APEX Set value to Page Item from Ajax process - oracle-apex

I'm trying to upload document from APEX page to S3 bucket and I'm successful with the help of plugin from https://www.apexutil.com/ords/prod/f?p=700:200:1349309139567:::::
The plugin demonstrate retrieve the upload result and inserting to table as explained below.
Create new dynamic action;
Choose Upload Success [FM Component];
Choose "Execute JavaScript Code" action;
Inside the "Code" textarea define code:
apex.server.process("my_ajax_process", {
x01: this.browserEvent.originalEvent.detail.serverId,
x02: this.browserEvent.originalEvent.detail.file.name,
x03: this.browserEvent.originalEvent.detail.file.body.size,
x04: this.browserEvent.originalEvent.detail.file.body.type
}, {
success: function() {
console.log("success");
},
and retrieve the x0 values in Ajax process and inserting to table.
Create Ajax Process, name: "my_ajax_process"
Define PL/SQL code:
declare
l_server_id varchar2(4000) := apex_application.g_x01;
l_name varchar2(4000) := apex_application.g_x02;
l_size number := apex_application.g_x03;
l_type varchar2(4000) := apex_application.g_x04;
begin
insert into MY_TABLE (MT_SERVER_ID, MT_NAME, MT_SIZE, MT_TYPE)
values (l_server_id, l_name, l_size, l_type);
owa_util.status_line(nstatus => 204, creason => 'No Content');
end;
However I need to capture the X0 values in the Ajax process and assign to Form pages items, as I have to store the output along with other form fields and store into my table. I have tried and however its not getting updated. Any help much appreciated
declare
l_server_id varchar2(4000) := apex_application.g_x01;
l_name varchar2(4000) := apex_application.g_x02;
l_size number := apex_application.g_x03;
l_type varchar2(4000) := apex_application.g_x04;
begin
:P12_DOCUMENTURL := l_server_id;
:P12_DOCUMENTTYPE := l_type;
:P12_DOCSIZE := l_size;
owa_util.status_line(nstatus => 204, creason => 'No Content');
end;

:P12_DOCUMENTURL := l_server_id; -- This kind of assignment wont work in an ajax process
But you can use APEX_UTIL.SET_SESSION_STATE
BEGIN
APEX_UTIL.SET_SESSION_STATE('my_item','myvalue');
END;
Example
BEGIN
APEX_UTIL.SET_SESSION_STATE('P12_DOCUMENTURL',l_server_id);
END;
More details here -
https://docs.oracle.com/cd/E37097_01/doc.42/e35127/GUID-62AA4333-160D-44FD-9F07-D188A2F4BC55.htm#AEAPI181
Also please take a look at this https://jeffkemponoracle.com/2014/02/apex_util-set_session_state-may-or-may-not-commit/
For some more discussion about the commits issued.

Finally this works for me.
A dynamic action
var l01 = this.browserEvent.originalEvent.detail.serverId;
var l03 = this.browserEvent.originalEvent.detail.file.body.size;
var l04 = this.browserEvent.originalEvent.detail.file.body.type;
apex.server.process
( "upload_ajax_process",
{},
{ success: function( pData ) {
$s("P12_DOCUMENTURL",l01 );
$s("P12_DOCSIZE", l03);
$s("P12_DOCUMENTTYPE", l04);
}
}
);
Also Ajax process "upload_ajax_process" with some dummy statement. Without this I'm getting "Error: SyntaxError: Unexpected token P in JSON at position 0"
begin
owa_util.status_line(nstatus => 204, creason => 'No Content');
end;

Related

Oracle Apex Getting JSON.WRITER.NOT_OPEN Error

I tried the following code in SQL workshop and it ran. I tried the same code in an application after removing DBMS_OUT_PUT using it in a set value action and I get the error message: Ajax call returned server error ORA-20987: APEX - JSON.WRITER.NOT_OPEN - Contact your application administrator.
Details about this incident are available via debug id "354017". for Set Value. However, the debug logs don't provide any additional details.
What am I missing? It worked in the application a few days ago.
declare
l_request_url varchar2(32767);
l_content_type varchar2(32767);
l_content_length varchar2(32767);
l_response varchar2(10000);
l_body_clob clob;
l_name varchar2(200);
download_failed_exception exception;
j apex_json.t_values;
n_customer_id number;
begin
l_request_url := 'https://mysterysite.com/api/v3/customer';
APEX_JSON.initialize_clob_output;
APEX_JSON.open_object;
APEX_JSON.write('company', :P5_COMPANY);
APEX_JSON.write('bill_addr1', :P5_BILL_ADDR1);
APEX_JSON.write('bill_addr2', :P5_BILL_ADDR2);
APEX_JSON.write('bill_city', :P5_BILL_CITY);
APEX_JSON.write('bill_postcode', :P5_BILL_POSTCODE);
APEX_JSON.write('superuser_email', :P5__YOUR_EMAIL);
APEX_JSON.close_object;
l_body_clob :=APEX_JSON.get_clob_output;
APEX_JSON.free_output;
apex_web_service.g_request_headers.delete();
apex_web_service.g_request_headers(1).name := 'Content-Type';
apex_web_service.g_request_headers(1).value := 'application/json';
l_response := apex_web_service.make_rest_request(
p_url => l_request_url
, p_http_method => 'POST'
, p_username => 'junk username'
, p_password => 'junkpassword'
, p_body => l_body_clob
);
if apex_web_service.g_status_code != 201 then
DBMS_OUTPUT.PUT_LINE('ERROR');
else
apex_json.Parse (j, l_response);
n_customer_id := apex_json.get_varchar2 (p_values => j, p_path => 'response.id');
DBMS_OUTPUT.PUT_LINE(n_customer_id);
end if;
end;
Product Build 22.2.1
Schema Compatibility 2022.10.07
Patch Version 1
Last Patch Time 12/26/2022 05:32:28 PM
Last DDL Time 12/26/2022 04:37:11 PM
Host Schema ORDS_PLSQL_GATEWAY
Application Owner APEX_220200
Not a complete solution, just a work around.
Replace the set value action with execute server side code action. In the code replace RETURN with apex_util.set_session_state ('item_name', value);
Try to set the preserve parameter to true in the call to initialize_clob_output.
In what context are you running this code? Another process probably also uses apex_json in the same code.

Oracle APEX manualy upload file

I have a problem with manually uploading the file from the SQL query. The file is sent to the database, but after re-filling the form (for the first time it only sends the completed form data). The file remains visible in the session and is as if stored until the next form filling. I know I can do this as Automatic Query Submission (DML) but I need to do it manually (I have a query that imports data into several tables at once)
DECLARE
l_blob BLOB;
l_filename VARCHAR2 (200);
l_mime_type VARCHAR2 (200);
l_token VARCHAR2 (32000);
BEGIN
l_filename := :P8_ATTACH;
l_mime_type := 'application/pdf');
DBMS_LOB.createtemporary (l_blob, FALSE, DBMS_LOB.SESSION);
FOR i IN 1 .. apex_application.g_f01.COUNT
LOOP
l_token := wwv_flow.g_f01 (i);
IF LENGTH (l_token) > 0
THEN
DBMS_LOB.append
(dest_lob => l_blob,
src_lob => to_blob
(UTL_ENCODE.base64_decode
(UTL_RAW.cast_to_raw (l_token)
)
)
);
END IF;
END LOOP;
IF DBMS_LOB.getlength (l_blob) IS NOT NULL
THEN
UPDATE REZERV
SET ATTACH = l_blob,
MIMETYPE = l_mime_type,
FILENAME = l_filename
WHERE ID = :P8_ID;
END IF;
END;
Have you considered
'Purge file at' = 'End of request'
or
'Source -> Used' = 'Always replacing session state'

How to call Jira Rest API from Oracle APEX Page

Requirement -
Below fields to be displayed on a APEX page for any Jira issue created.
Issue Number/Issue Id
Summary
Description
Status
Assignee
Example, user01 and user02 both having access to Oracle APEX and Jira. user01 created 3 issues and user02 created 5 issues in Jira. Now when user01 who logs into Oracle APEX, should see 3 issues and when user02 who logs into Oracle APEX, should see 5 issues on a APEX page.
https://jira.local.com/jira/rest/api2
I'm new to APEX Rest service call and request to all of you to provide some sample APEX code to call Jira REST API using username/password for the above requirement.
Thanks all.
I have done something similar before. In my case, the goal was to get all the issues of project PRJ001 (Jira Project Key) from Jira and store them in a local database table (J_ISSUES), periodically, so I've created a Job that executed the following procedure from time to time:
create or replace PROCEDURE "JIRA_SYNC_ISSUES" as
var_response CLOB;
var_counter number := 0;
var_total number := 1;
var_prj_key varchar2(10);
begin
var_prj_key := 'PRJ001';
var_total := 1;
var_counter := 0;
while var_total > var_counter
loop
apex_session.create_session (p_app_id => 107, p_page_id => 1, p_username => 'USERNAME01');
var_response:= apex_web_service.make_rest_request(
p_url => 'https://yourcompany.atlassian.net/rest/api/2/search?jql=project="'|| var_prj_key ||'"&maxResults=100&startAt=' || var_counter || '',
p_http_method => 'GET',
p_credential_static_id => 'oud_rest'
);
SELECT JSON_VALUE(var_response, '$.total' RETURNING NUMBER) into var_total
FROM DUAL;
for i in (SELECT *
FROM
JSON_TABLE(var_response, '$.issues[*]'
COLUMNS (
key VARCHAR2(100) PATH '$.key',
prj_key VARCHAR2(100) PATH '$.fields.project.key',
status VARCHAR2(100) PATH '$.fields.status.name',
updated VARCHAR2(100) PATH '$.fields.updated',
assignee VARCHAR2(100) PATH '$.fields.assignee.name',
time_spent NUMBER PATH '$.fields.timespent'
)))
loop
begin
insert into j_issues (jis_key, jis_jpr_key, jis_status, jis_updated, jis_assignee, jis_time_spent)
values (i.key,
i.prj_key,
i.status,
to_timestamp(substr(i.updated,1,10)||' '||substr(i.updated,12,8),'YYYY-MM-DD HH24:MI:SS'),
i.assignee,
i.time_spent);
exception
when dup_val_on_index then
update j_issues
set jis_jpr_key = i.prj_key,
jis_status = i.status,
jis_updated = to_timestamp(substr(i.updated,1,10)||' '||substr(i.updated,12,8),'YYYY-MM-DD HH24:MI:SS'),
jis_assignee = i.assignee,
jis_time_spent = i.time_spent
where jis_key = i.key;
end;
var_counter := var_counter + 1;
end loop;
end loop;
end jira_sync_issues;
In the first part it is authenticating and making the call to the API. In the second, it takes the var_response and inserts it into the required table.
For the first part, I've read this: https://www.jmjcloud.com/blog/simplifying-apex_web_service-oauth2-client-credentials
For the second: https://docs.oracle.com/database/121/SQLRF/functions092.htm
Notice the var_counter and var_total variables. They are used to iterate through the Jira responses, because there is a limit of items being retrieved in each response. So, if you are expecting more than that limit, you should make more calls to retrieve them.
If the volume of issues is big, there are advantages in doing a scheduled sync like this instead of letting the user wait for the entire result. After the data is in your database, you can just query it as usual.
Let me know if it helps ;)

Alert message after submit and validation page in oracle apex

I have a dynamic action doing the below ,
Submit page ,
Successful Alert message,
Log out and redirect to another website (www.google.com),
And I have two required item in page.
When pressed the button and the item is null ,the successful Alert message appears and after that the system shows the error (the item is required). How can I show the successful alert message only when the process and validation are done without errors ,and when ok is pressed in the alert message redirect to website and log out from the sessions
There are different ways you could approach this. You're currently using a mix of Dynamic Actions and page-level validations and processes that aren't going to play well together. I suggest you move all the logic to Dynamic Actions. Here are step by step instructions to do what I think you're trying to do. You can learn from this and then integrate what you want back to your solution.
Create a new blank page. Mine was page 17. You'll need to update references to "P17" with your page number if it's different. Disable the page level attribute Warn on Unsaved Changes to prevent prompts before the redirect to Google.
Add a new HTML region to the page.
Add a new item to the region. Set Name to P17_FIRST_NAME and leave the default Type of Text Field.
Add a new item to the region. Set Name to P17_LAST_NAME and leave the default Type of Text Field.
Add a new item to the region. Set Name to P17_RESULT, Type to Hidden, and Value Protected to No. This item will be used to transfer messages from the server to the client via Ajax.
Add a button to the region. Set Name to RUN_PROCESS and Action to Defined by Dynamic Action.
Create a new Dynamic Action that fires when the button is clicked. The easiest way to do this is to right-click the button and select Create Dynamic Action. Set the Name to RUN_PROCESS clicked.
Select the Show action that was created by default for the Dynamic Action. Set Action to Execute PL/SQL Code and copy-paste the following code into the PL/SQL Code attribute.
declare
l_result_obj json_object_t := json_object_t();
l_errors_arr json_array_t := json_array_t();
l_error_obj json_object_t;
begin
if :P17_FIRST_NAME is null
then
l_error_obj := json_object_t();
l_error_obj.put('pageItem', 'P17_FIRST_NAME');
l_error_obj.put('message', 'First Name is required.');
l_errors_arr.append(l_error_obj);
end if;
if :P17_LAST_NAME is null
then
l_error_obj := json_object_t();
l_error_obj.put('pageItem', 'P17_LAST_NAME');
l_error_obj.put('message', 'Last Name is required.');
l_errors_arr.append(l_error_obj);
end if;
if l_errors_arr.get_size() > 0
then
l_result_obj.put('status', 'error');
l_result_obj.put('errors', l_errors_arr);
:P17_RESULT := l_result_obj.to_string();
return;
end if;
null; -- do "success" processing here
l_result_obj.put('status', 'success');
l_result_obj.put('message', 'Hi ' || :P17_LAST_NAME || ' ' || :P17_LAST_NAME ||
'! You will now be redirected to Google.');
:P17_RESULT := l_result_obj.to_string();
end;
As you can see, the validations are now being done inside the process. The PL/SQL code is making use of the JSON types introduced with Oracle 12.2. If you're on an older version of the database, you can adapt the code to use APEX_JSON instead.
While still in the Execute PL/SQL Code action, set Items to Submit to P17_FIRST_NAME,P17_LAST_NAME and Items to Return to P17_RESULT. This is how you can transfer values from the page into session state before the process executes and then back to the page after the process finishes executing.
Create a new Dynamic Action that fires on the Change event of P17_RESULT. The easiest way to do this is to right-click the item and select Create Dynamic Action. Set the Name to P17_RESULT changed.
Select the Show action that was created by default for the Dynamic Action. Set Action to Execute JavaScript Code and copy-paste the following code into the Code attribute.
var result = JSON.parse($v('P17_RESULT'));
apex.message.clearErrors();
if (result.status === 'error') {
for (var idx = 0; idx < result.errors.length; idx++) {
result.errors[idx].type = 'error';
result.errors[idx].location = ['page', 'inline'];
result.errors[idx].unsafe = false;
}
apex.message.showErrors(result.errors);
} else if (result.status === 'success') {
apex.message.alert(result.message, function(){
apex.navigation.redirect('https://google.com');
});
}
The JavaScript code takes the result from the process and either displays error messages or an alert. I'm using apex.message.alert instead of apex.message.showPageSuccess because the former supports a callback when the message is dismissed. When the message is dismissed, apex.navigation.redirect takes the user to Google.
Here's what it should look like in the end:
I hope there's enough information here for you to understand what's going on. Let me know if you have any questions. You'll find the documentation for apex.navigation and apex.message here: https://apex.oracle.com/jsapi
P.S. Here's an example of what the PL/SQL code would look like using APEX_JSON.
declare
l_error_count pls_integer := 0;
l_result_obj clob;
begin
apex_json.initialize_clob_output;
apex_json.open_object();
apex_json.open_array('errors');
if :P17_FIRST_NAME is null
then
l_error_count := l_error_count + 1;
apex_json.open_object();
apex_json.write('pageItem', 'P17_FIRST_NAME');
apex_json.write('message', 'First Name is required.');
apex_json.close_object();
end if;
if :P17_LAST_NAME is null
then
l_error_count := l_error_count + 1;
apex_json.open_object();
apex_json.write('pageItem', 'P17_LAST_NAME');
apex_json.write('message', 'Last Name is required.');
apex_json.close_object();
end if;
apex_json.close_array();
if l_error_count > 0
then
apex_json.write('status', 'error');
apex_json.close_object();
:P17_RESULT := apex_json.get_clob_output();
apex_json.free_output;
return;
end if;
null; -- do "success" processing here
apex_json.write('status', 'success');
apex_json.write('message', 'Hi ' || :P17_LAST_NAME || ' ' || :P17_LAST_NAME ||
'! You will now be redirected to Google.');
apex_json.close_object();
:P17_RESULT := apex_json.get_clob_output();
apex_json.free_output;
end;

APEX - how to call store procedure base on values of items on the page

similiar problem has already been mentioned, described and solved here using dynamic actions but I still can't implement it in my case.
I have a form (created authomatically but page creator) to change password in remote database. There are three items
login : P15_UNAME (select list) LOV
new password: P15_NEW (password)
button to execute: SUBMIT (button).
Button fires a simple stored procedure:
declare
success int;
msg varchar(100);
begin
SYS.CHANGEPASSWORD#abc(
PUSERNAME => :P15_UNAME,
PNEWPASSWORD => :P15_NEW,
PRESULT => success,
PMESSAGE => msg);
if success = 0 then
apex_application.g_print_success_message := msg;
else
apex_application.g_print_success_message := '<span style="color:red">' || msg || '</span>';
end if ;
end ;
Unfortunately choosen/typed values of login and password are not called by stored procedure. I probably should use dynamic action but have no idea how to call store procedure and dynamic simultaneously. Could you give me some hints please.
K.
Are you trying to pass the page item values directly into the database? Your procedure / procedure call should look something like this.
-- database
PROCEDURE p_change_details(p_uname varchar2, p_password varchar2)
IS
success int;
msg varchar(100);
begin
SYS.CHANGEPASSWORD#abc(
PUSERNAME => p_uname,
PNEWPASSWORD => p_password,
PRESULT => success,
PMESSAGE => msg);
if success = 0 then
apex_application.g_print_success_message := msg;
else
apex_application.g_print_success_message := '<span style="color:red">' || msg || '</span>';
end if ;
end ;
--APEX
p_change_details(:P15_UNAME, :P15_NEW)
You can create a Dynamic Action to execute a PL/SQL code on button click.
refer this example- Link
Hope this will help you. Let me know for any question.