Reputation: 631
I'm having an issue binding the value of a page item to a declared variable in an anonymous PL/SQL block process.
The problem is that the page item (:P4550_REQUESTOR) is not populated with a value until a conditional is met. It appears that the PL/SQL block process is binding the variable to an empty value as soon as the page is loaded, despite the fact that the process does not fire until a specific button has been clicked.
Here is my code:
DECLARE
v_email_to app_user.email%type;
v_requestor VARCHAR2(15);
BEGIN
v_requestor := :P4550_REQUESTOR;
BEGIN
SELECT email INTO v_email_to
FROM app_user
WHERE userid = v_requestor;
END;
SEND_APEX_MAIL (
v_email_to,
'Your vacancy request has been rejected.'
|| chr(10)
|| 'Emailed to: ' || v_email_to
|| chr(10)
|| 'Requestor: ' || v_requestor,
'Vacancy Request Rejected'
);
END;
Does anyone have any thoughts on this?
The block works just fine if I hard code a value to v_requestor. If I try to get the value of P4550_REQUESTOR after the page has loaded, it is empty. After clicking the edit button, P4550_REQUESTOR is populated.
** **MORE DETAIL** **
P4550_REQUESTOR is a page item that resides within the Vacancy Request region which is only displayed when a conditional is met. Specifically, the conditional is an edit button associated with a table row that is created on page load. Clicking the edit button causes the details region to display, and the associated page items to be populated.
The page item values in the Vacancy Request region are populated via an Automated Row Fetch which fires After Header.
P4550_REQUESTOR has a Source Type of DB Column.
The process that fires the code above is set to fire On Submit - After Computations and Validations
If I log the value of P4550_REQUESTOR when the page loads, it shows null. If I log the value after clicking the edit button, I get the expected string value.
Upvotes: 2
Views: 5760
Reputation: 5055
The original, verbose answer seems to way overcomplicate the issue. The session state concepts manual covers this behaviour more succinctly.
Should P4550_REQUESTOR be a normal item created from a wizard, using :P4550_REQUESTOR will return a value in processes running post submit because the submit processes moves values in browser to session state.
If P4550_REQUESTOR is rendered conditionally, then it will always be null and I'm not sure what would happen if you tried to set it - probably depends how.
On a similar note, if you used &P4550_REQUESTOR. to parameterise the process, you would face the behaviour originally described (and made the code less secure)
Upvotes: 0
Reputation: 2021
(This is actually useful to think about in other programming disciplines and environments.)
The problem is that the page item (:P4550_REQUESTOR) is not populated with a value until a conditional is met. It appears that the PL/SQL block process is binding the variable to an empty value as soon as the page is loaded, despite the fact that the process does not fire until a specific button has been clicked.
The problem statement reworded in Apex terminology and presented in the form of an actual question:
- There is a
REPORT REGION
on the page which contains the result of a direct reference to a data table/view. This report is managed by an Apex process called "Automated Fetch" and is initiated automatically by the loading of the page headers.- There is a
FORM ITEM
on a page which which is populated conditionally by aBUTTON ITEM
selection made by the user. TheBUTTON ITEM
is part of the report results.- There are multiple button items. Each is associated with a value for each report record.
- If the user does not select the
BUTTON ITEM
from theREPORT REGION
, theFORM ITEM
remains unassigned and contains a "null" value.
There is a defined PL/SQL block of code which is set to execute when a SUBMIT BUTTON
item is pressed (also on the same page). Why does my code block (defined page process) run with a null value when it is triggered without first pressing a BUTTON ITEM
from the REPORT REGION
first?
The answer is not obvious if you think under the paradigm of a procedural language. Without diving into a lecture on the topic, here's a visual layout of the problem space of the OP that I cooked up to illustrate how the problem can be made more obvious:
This is my Apex page design in implementation. It's generic enough to use as a template for other Apex designs. There are no flow arrows on this diagram because it's a stateful system. One thing causes another thing to happen and so on... but not always and not all at the same time.
Try walking through a few use cases to understand how the elements broken down in the diagram operate together. Each user may take any number of click combinations and interactions, but there is a commonality:
Use Case #1
{MyPage:SQLReport:ThisButton}
from one of the records in {MyPage:SQLReport}
{MyPage:SQLReport:ThisButton} #3
, the value associated between the report record and the button item is passed to: {MyPage:HTML-Region:ThisItem}
{MyPage:HTML-Region:ThisSubmit}
button to inform the system to continue on.{MyPage:RunCodeBlock}
Use Case #2
{MyPage:SQLReport}
region.{MyPage:HTML-Region:ThisSubmit}
button to inform the system to continue on.{MyPage:HTML-Region:ThisItem}
has not been changed from the initial null value at this point... after the submit button has been selected){MyPage:RunCodeBlock}
Use Case #3
{MyPage:SQLReport:ThisButton}
from one of the records in {MyPage:SQLReport}
{MyPage:SQLReport:ThisButton} #3
, the value associated between the report record and the button item is passed to: {MyPage:HTML-Region:ThisItem}
{MyPage:SQLReport:ThisButton}
from a different selection from one of the records in {MyPage:SQLReport}
.{MyPage:SQLReport:ThisButton} #3
, the value associated between the report record and the button item is passed to: {MyPage:HTML-Region:ThisItem}
{MyPage:HTML-Region:ThisSubmit}
button to inform the system to continue on.{MyPage:RunCodeBlock}
The difference between each case should illustrate why the dependent value (ThisItem
, or more specifically, page item P4550_REQUESTOR
) is null in one use case vs. the other.
The table I used is called STAR_EMPS. It is similar to the EMP table but has only three columns: ename, deptno and salary. Although it is not super important, this is the data set I used to populate STAR_EMPS:
I used a simple two-column table named STAR_EMPS_LOG for capturing the output of a successfully executed procedure call. You could accomplish the same with just one column, but I wanted a sequential id for tracking the order each event was recorded- for running multiple test cases. The procedure is one of several defined processes kept on this page:
contained in: {MyPage:RunCodeBlock} is below:
DECLARE
-- output from this procedure will be recorded in the star_emps_log
-- table. {MyPage:RunCodeBlock}
mycelebrity star_emps.ename%TYPE:= :P17_CELEBRITY_NAME;
mylogmessage star_emps_log.log_message%TYPE;
BEGIN
-- Conditional; changes message based on the value set for the
-- page item.
if mycelebrity is null then
mylogmessage:= 'No button was pressed on the previous page.';
else
mylogmessage:= 'The user selected: ' || mycelebrity ||
' from the report list.';
end if;
-- populate value from the page item.
INSERT INTO star_emps_log (log_message)
VALUES (mylogmessage);
commit;
END;
This is how the page layout was set up:
The TWO Page processes: PROCESS and BRANCH need to be linked with the same settings referencing a BUTTON triggering Item.
Run through the three suggested scenarios to get started. Verify that the system is interpreting the requests correctly. This is what the page layout looks like:
The two processes on the system have a definition that wasn't mentioned in previous discussions may solve our original problem at hand:
It is a good thing this turns out to be a trivial case once broken down. The diagramming method described here should scale to other Apex applications of varying complexity. There is considerable utility in stepping away from the code, locking down on terminology and trying to describe systems and processes without actual code. Please be sure to share any stories if this approach helps with your own Oracle Apex design challenges.
Onward!
Upvotes: 3