Using APEX_CUSTOM_AUTH.APPLICATION_PAGE_ITEM_EXISTS in external Package - APEX 21.2 - oracle-apex

I have a page where the following page item, :P10_ACCOUNT_CHANGED_FLAG, is not always rendered on the page (using Server Side condition). I have an external package that references this page.
I am trying to check for the existence of the page item. If it exists, then set form value to a global package variable, g_changed_flag in the package. If not, then default value to 'N'.
I was trying to use:
l_page_item_exists := apex_custom_auth.application_page_item_exists(:P10_ACCOUNT_CHANGES_FLAG);
if l_page_item_exists then
g_change_flag := v('P10_ACCOUNT_CHANGES_FLAG');
else
g_change_flag := 'N';
end if;
But it throws the following error:
PLS-00049: bad bind variable 'P10_ACCOUNT_CHANGES_FLAG'
Any advice?

You're looking for an item, not its value.
Try
l_page_item_exists :=
apex_custom_auth.application_page_item_exists('P10_ACCOUNT_CHANGES_FLAG');
instead.

Related

Apex : How to display an error on a page Item created dynamically?

I'm running Apex 19.2
I have a page with some items created dynamically as follows :
HTML clob;
Html := APEX_ITEM.textarea(p_idx=>32, p_value=>'MyValue',p_item_id=>'MyId',p_attributes=>'class="textarea"');
htp.p(HTML);
The page items are generated correctly :
<textarea name="f32" rows="4" cols="40" wrap="VIRTUAL" class="textarea" id="MyId"></textarea>
I'm also adding the item wrapper to match the static Items layout created from the designer.
<div class="t-Form-inputContainer col">
<div class="t-Form-itemWrapper">
<textarea name="f32" rows="4" cols="40" wrap="VIRTUAL" class="textarea" id="MyId"></textarea>
</div>
<span id="MyId_error_placeholder" class="a-Form-error"></span>
</div>
In the validation, I'm checking some rules from apex_application.g_fn arrays and I would like to show an error on the item created via :
apex_error.add_error(p_message => 'error', p_display_location => apex_error.c_inline_with_field_and_notif, p_page_item_name=> 'MyId');
After validation, the error is not shown next to the item created. Notification also appears but it's empty. However If I try to show the same error on a static item created in the designer. The error is shown properly.
Can anyone help please ?
Thanks.
As you've found, APEX_ITEM doesn't work with APEX_ERROR in the way that you'd like it to. Marc's comments here indicate that APEX_ITEM will likely not be developed further, so it probably never will. https://stackoverflow.com/a/61737128/3010084
Your best option might be to move your validation logic to a stored procedure. Do all the validation in one call via parameters. In addition to the regular parameters, add a parameter that indicates if the response should be JSON or not. If so, just return a JSON document with the errors, otherwise use apex_error. This will allow you to call the validation logic via Ajax to show the errors where you like, but also on submit/page processing (because client-side validation can't be trusted).
Here are some steps you can follow to see how this works... First, compile the following procedure in your schema:
create or replace procedure validate_thing(
p_description in varchar2,
p_return_json in boolean,
p_json_result out json_object_t
)
is
l_errors_arr json_array_t := json_array_t();
l_error_obj json_object_t := json_object_t();
l_item_id varchar2(30);
l_error_message varchar2(255);
begin
if length(p_description) > 10
then
l_item_id := 'description';
l_error_message := 'Description should be less than 10 characters.';
if p_return_json
then
l_error_obj := json_object_t();
l_error_obj.put('pageItem', l_item_id);
l_error_obj.put('message', l_error_message);
l_errors_arr.append(l_error_obj);
else
-- Server-side code will not worry about displaying the error with the item as
-- this is just a backup for the client-side validation
apex_error.add_error(
p_message => l_error_message,
p_display_location => apex_error.c_inline_in_notification
);
end if;
end if;
if p_return_json
then
p_json_result := json_object_t();
if l_errors_arr.get_size() > 0
then
p_json_result.put('status', 'error');
p_json_result.put('errors', l_errors_arr);
else
p_json_result.put('status', 'success');
end if;
end if;
end;
As you can see, the procedure has logic to do client-side validations (JSON) or server-side validation (APEX_ERROR). You would need to add additional parameters and logic as needed for the form.
Create a new blank page in your app and go to the Page Designer for the new page. Right-click Content Body (under Regions) and select Create Region. Set the region's Type to PL/SQL Dynamic Content and add the following code to the PL/SQL Code attribute:
declare
html clob;
begin
-- The div and fieldset wrappers are needed so that APEX will generate an error
-- message template automatically to display the error inline.
html := '<div><fieldset>';
html := html || APEX_ITEM.textarea(p_idx=>32, p_value=>'MyValue',p_item_id=>'description',p_attributes=>'class="textarea apex-item-textarea"');
html := html || '</fieldset></div>';
htp.p(html);
end;
That code uses apex_item to add an item to the page dynamically. Note, the value passed to p_item_id, as that's important. The apex-item-textarea class is needed for error styling and the div and fieldset wrappers are needed to display error messages inline.
Select the Processing tab in Page Designer. Right-click Ajax Callback and select Create Process. Set Name to DO_VALIDATIONS and enter the following code in the PL/SQL Code field.
declare
l_result json_object_t;
begin
validate_thing(
p_description => apex_application.g_x01,
p_return_json => true,
p_json_result => l_result
);
htp.p(l_result.to_string());
end;
That is the code that will call validate_thing with p_return_json set to true. Note that the value of "description" is being passed in via apex_application.g_x01. You have g_x01 - g_x20 to work within this way. There are various options you could leverage to sent values in via Ajax, this is just one example. See see the doc on apex.server.process (used next) for more info.
Return to the rendering tab, right-click the new region, and select Create Button. Set the Button Name to SUBMIT. Right-click the SUBMIT button and select Create Dynamic Action. Set the Name to SUBMIT clicked. Select the default Show action, set its Action to Execute JavaScript Code, then add the following code to the Code field:
apex.server.process(
'DO_VALIDATIONS',
{
x01: $x('description').value
},
{
success: function(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.page.submit('SUBMIT');
}
},
error: function( jqXHR, textStatus, errorThrown ) {
console.log(jqXHR, textStatus, errorThrown)
}
}
);
This is the JavaScript code that will invoke the new DO_VALIDATIONS Ajax process. If errors are returned from the server, apex.message.showErrors will display them. Otherwise, the page is submitted for processing.
Select the Processing tab, right-click Processing, and select Create Process. Set Name to Do Validations and enter the following code in the PL/SQL Code attribute:
declare
-- Only needed to call validate_thing, not used.
l_result json_object_t;
begin
validate_thing(
p_description => apex_application.g_f32(1), -- This is where the item's value will be when submitting normally
p_return_json => false, -- This tells validate_thing to use apex_error
p_json_result => l_result
);
end;
That code will invoke validate_thing with p_return_json set to false. This will rerun the validations on the server-side to ensure they are enforced there. As it's just a backup for the client-side call, I don't worry about displaying errors inline with the items (the JS will do that).
Right-click Processing again and select Create Process. Set Name to Do Work and just enter null; for the PL/SQL Code Attribute. Set Success Message to It ran.. Under Server-side Condition, set Type to PL/SQL Expression and enter not apex_error.have_errors_occurred in the PL/SQL Expression field.
This process represents the actual business logic you want to run after validations have passed. You will only see the success message after clicking submit if both the Ajax and server-side validations have passed.
If you wish the test the server-side validations, add this line of JavaScript code in the Dynamic Action, just before the line that submits the page:
$x('description').value = '12345678910';
That will update the value of the text area to exceed the limit enforced by the server.

Oracle APEX - issue accessing html control from a DA condition

I have a custom DA that is called when JavaScript expression is document and I want it to execute only when a specific client-side condition is met.
So I set the client-side condition to javascript expression:
document.getElementById("myfield").options[status.selectedIndex].text != "Closed"
The issue is that myfield is no a page item, but rather an html control - a select box. So I have to use javascript expression instead of Item != Value.
Now when I run the page and attempt to perform the action that activates my DA, the condition is being checked and it errors out saying Cannot read property 'text' of undefined. How can I change my javaScript expression to get it to work?
In APEX, $x is a shorthand reference/pointer to document.getElementById, so you should be able to do this:
$x("myfield").options[$x("myfield").selectedIndex].text != "Closed"
When using JavaScript expression, if you need to do more than just a basic expression, you can use an Immediately Invoked Function Expression to break down the logic. Here's an example:
(function(){
var select = $x('page-item-id');
if (select.selectedIndex === -1) {
return false;
}
return select.options[select.selectedIndex].text != 'Closed';
})()
Alternatively, you could declare a function in the Function and Global Variable Declaration attribute of the page and then invoke it as an expression in the Condition of a DA.

How i can display pdf file into region oracle apex?

i want display PDF file into region , i tried that by call application process using below code but always same file open.( plsql dynamic content region)
DECLARE
V_URL VARCHAR2(2500);
BEGIN
V_URL :='f?p=&APP_ID.:1:&APP_SESSION.:APPLICATION_PROCESS=display_emp_blob:::FILE_ID:' ||:P6_ID;
Sys.htp.p('<p align="center">');
sys.htp.p('<iframe src="'||V_URL||'"width="99%" height="1000">');
sys.htp.p('</iframe>');
sys.htp.p('</p>');
END;
and the application process code in below
CREATE OR REPLACE PROCEDURE OPEN_FILE (P_ID NUMBER)
IS
vBlob blob;
vmimetype varchar2(50);
BEGIN
SELECT ORG_FILES.FILE_CONTENT,MIME_TYPE INTO vBlob, vmimetype
FROM ORG_FILES
WHERE ID =P_ID ;
sys.HTP.init;
owa_util.mime_header(vmimetype,false);
htp.p('Content-Length: ' || dbms_lob.getlength(vBlob));
owa_util.http_header_close;
wpg_docload.download_file(vBlob);
apex_application.stop_apex_engine;
exception
when no_data_found then
null;
END;
How i can open different PDF file into region based a value in ITEM (P6_ID) .
I think the problem you have is that the browser caches the file.
You can specify the time the browser caches with the "Cache-control" header option. Below, you have the code that I use (I have this code in the application process, not in the database):
sys.htp.init;
sys.owa_util.mime_header( 'application/pdf', FALSE );
sys.htp.p('Content-length: ' || sys.dbms_lob.getlength( v_blob));
sys.htp.p('Content-Disposition: inline; filename="'|| v_filename || '"' ); -- "attachment" for download, "inline" for display
sys.htp.p('Cache-Control: max-age=3600'); -- in seconds. Tell the browser to cache for one hour, adjust as necessary
sys.owa_util.http_header_close;
sys.wpg_docload.download_file( v_blob );
apex_application.stop_apex_engine;
You can also try some lazy load, which is the way I access my files (It may be that the way to access your file is also part of the problem). This way you make the page load without waiting for the user and then it loads and shows the file. I don't use the iframe tag but the embed tag. The way to do it is as follows:
Create a region with static content with this html
<div id="view_pdf"></div>
creates a dynamic action when the page loads, which executes javascript and add the following code
$('#view_pdf').html('');
var url = 'f?p=&APP_ID.:1:&APP_SESSION.:APPLICATION_PROCESS=display_emp_blob:::FILE_ID:' + apex.item('P6_ID').getValue();
var preview = document.createElement('embed');
preview.type = "application/pdf";
preview.width="100%";
preview.height="625px";
preview.src = url;
$("#view_pdf").append(preview);
You can modify the values depending on what you need. The embed tag uses the default way to view pdf files from browsers.
Also if what you want is to change the pdf without reloading the page you must use the previous javacript in a dynamic action when you change the value of the item.
I hope you find it useful.
My apologies, on the rare occasion I use this region type, I always think it can be refreshed.
https://spendolini.blogspot.com/2015/11/refreshing-plsql-regions-in-apex.html
The solution is to create a classic report that calls a PL/SQL function that returns your HTML.
SELECT package_name.function_name(p_item => :P1_ITEM) result FROM dual

How to add form alter hook in drupal 8

I am very much new to drupal 8, I am trying to alter a form under custom content type "Question". The form has an id "node-question-form".
I have setup a module and trying to add hook_FORM_ID_alter() but its never getting called. Even the simplest hook is not working. eg:
function constellator_form_alter(&$form, &$form_state, $form_id){
echo "alter the form"; exit;
}
where 'constellator' is the module name.
I have been stuck with since morning and nothing is working for me, Any help will be greatly appriciated.
Cheers
hook_form_alter() and hook_FORM_ID_alter() are called while a form is being created and before displaying it on the screen.
These functions are written in the .module file.
Always clear the cache after writing any hook function. This makes Drupal understand that such a function has been declared.
Use drush cr if using drush version 8 else click on Manage->Drupal 8 logo->Flush all Caches to clear the caches.
Now you can check if the function is being called or not.
The best way to check that is to install the Devel module, enable it. Along with Devel, Kint is installed. Enable Kint too from the Admin UI.
After doing that,you can check whether the hook is being called or not in the following way:
function constellator_form_alter(&$form, &$form_state, $form_id){
kint($form);
}
This will print all the form variables for all forms in the page.
If you want to target a particular form in the page, for eg. you form, node-question-form, type:
function node_question_form_form_alter(&$form, &$form_state, $form_id){
kint($form);
}
Using echo, the way you did, you can confirm whether the function is being called or not, without any hassle, by viewing the Source Code for the page and then searching for the text that you have echoed, using some search option of browser, like, Ctrl+f in case of Google Chrome.
If you want to change sorting options and/or direction (ASC / DESC), you can use this example (tested with Drupal 9).
Here I force the sorting direction according to the "sort by option" set by the user in an exposed filter. (if the user want to sort by relevance, we set the order to ASC, if the user want to sort by date, we set the order to DESC to have the latest content first).
/**
* Force sorting direction for search by date
*
*/
function MYTHEME_form_alter(&$form, &$form_state, $form_id)
{
if (!$form_id == 'views_exposed_form"' || !$form['#id'] == 'views-exposed-form-search-custom-page-1') {
return;
}
$user_input = $form_state->getUserInput();
if (empty($user_input['sort_by'])) {
return;
}
if ($user_input['sort_by'] == 'relevance') {
$user_input['sort_order'] = 'ASC';
} elseif ($user_input['sort_by'] == 'created') {
$user_input['sort_order'] = 'DESC';
}
$form_state->setUserInput($user_input);
}
Note that "views-exposed-form-search-custom-page-1" is the id of my form,
"relevance" and "created" are the sort field identifier set in drupal admin.
function hook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface &$form_state, $form_id) {
echo 'inside form alter';
}

Read-only condition not working

I'm developing an Oracle Application express (APEX 4.2) application.
One of the page controls (text box, title) have a "PL/SQL Expression" read-only condition:
:APP_PROJECT_READ_ONLY = 'YES'
:APP_PROJECT_READ_ONLY is an application item and it's set from a dynamic action on_load which fires on page load:
DECLARE
CURR_USER VARCHAR2(50);
BEGIN
IF :REQUEST = 'NEW' THEN
:APP_PROJECT_ID := 0;
:APP_PROJECT_READ_ONLY := 'NO';
ELSE
:APP_PROJECT_ID := :P2_ID;
SELECT OWNER INTO CURR_USER
FROM PROJECTS
WHERE ID = :APP_PROJECT_ID;
IF CURR_USER = :APP_USER THEN
:APP_PROJECT_READ_ONLY := 'NO';
ELSE
:APP_PROJECT_READ_ONLY := 'YES';
END IF;
END IF;
EXCEPTION WHEN NO_DATA_FOUND THEN
NULL;
END;
Checking session state shows that :APP_PROJECT_READ_ONLY's value is correct, but it doesn't seem to drive whether title is read only:
If I leave on_load's "page items to return" blank, then title is always editable.
However if I set it to title, then title will be always read-only and also it's source control doesn't work, it's leaved empty (in previous case it was working correctly).
How can I fix it?
Your problem is chronology.
The page renders, conditions evaluated, then you calculate your application item on the browser's page load.
Move your code into a computation, perhaps before regions, hence done as part of page render.
REQUEST values are organically only available in page processing, so unless you're explicitly setting that, it may be something to look out for.
You should also consider using declarative actions, where possible.
www.grassroots-oracle.com/2013/05/performance-of-apex-conditions.html