I have a page item P2_ITEM_TYPE_ID that gets set in Pre-Render, using a process calling PL/SQL:
BEGIN
select ITEM_TYPE_ID INTO :P2_ITEM_TYPE_ID from TABLE1 where ITEM_ID = :P2_ITEM_ID;
exception
when no_data_found then
:P2_ITEM_TYPE_ID := null;
END;
Currently the record for that ITEM_ID does not exist in TABLE1 so the exception NO_DATA_FOUND is thrown and originally the ITEM_TYPE_ID is set to null.
Now I want to set the ITEM_TYPE_ID by clicking on one of the cards on the page, grabbing its ID and setting page item P2_ITEM_TYPE_ID to that ID.
I have a dynamic action that runs the following javascript when card is clicked:
var $item_type_id = this.data;
console.log($item_type_id); //prints out correect ID
apex.item("P2_ITEM_TYPE_ID").setValue($item_type_id);
console.log(apex.item("P2_ITEM_TYPE_ID").getValue()); //prints out correct value
//set session state of P2_ITEM_TYPE_ID
apex.server.process ( "SAVE_HIDDEN_VALUE_IN_SESSION_STATE",
{
x01: $item_type_id,
pageItems: "#P2_ITEM_TYPE_ID"
},
{dataType: 'text'} );
I know the code works, as the correct values get printed to the console, but when I check the session of the page, P2_ITEM_TYPE_ID is blank in session. What could be the problem?
It is almost as if something is preventing th value from changing.
I have identical setup on another page with one small difference - the code in the pre-render does not include the exception part because there is always a record in TABLE1 for that ITEM_ID:
BEGIN
select ITEM_TYPE_ID INTO :P3_ITEM_TYPE_ID from TABLE1 where ITEM_ID = :P3_ITEM_ID;
END;
But the rest of the code is identical and session of P3_ITEM_TYPE_ID changes without an issue
You don't need apex.server.process for this, you can post the value of an item to the server with an Execute PL/SQL Code action that follows the javascript action you already have. Put the item name (e.g. P2_ITEM_TYPE_ID) in the Items to Submit attribute (set PL/SQL Code to just null;).
If everything is the same on those pages, except the EXCEPTION part, well - there's a workaround: use an aggregate function, e.g.
select max(ITEM_TYPE_ID) INTO :P2_ITEM_TYPE_ID from TABLE1 where ITEM_ID = :P2_ITEM_ID;
It will prevent the query from returning NO_DATA_FOUND if there's no value for that :P2_ITEM_ID and will store NULL into the :P2_ITEM_TYPE_ID.
Related
I have an application in which a user creates a form, for which several responsible persons are selected in this form and can edit this form.
As soon as the form is submitted, the corresponding page of the process is changed.
The page of the form and the respective responsible persons are saved in a separate table.
The function has to check whether the logged-in user with the user ID is entered in the table as one of the responsibles. The table for example Responsible1 contains a foreign key to the table USERS, in which the ID is located. As soon as it finds the responsible in the table, the function then should redirect the user to the corresponding page.
create or replace function forward_user(p_username in varchar2)
return varchar2
is
l_user varchar2(255);
l_branch_page number;
begin
l_user :=p_username;
/*
Get the target page depending on entry in table
*/
select
page
into l_branch_page
from
FORM_PAGES
where EXISTS (SELECT f.RESP1 from FORM f
left outer join RESPONSIBLE1 s on s.RESP1=f.RESP1
LEFT OUTER JOIN USERS u on u.ID=s.ID where lower(u.USERNAME) =lower(l_user) )
OR (fp.RESP2 in
(SELECT f.RESP2 from FORM f
left outer join RESPONSIBLE2 p on p.RESP2=f.RESP2
left outer join USERS u on u.ID=p.ID where lower(u.USERNAME) =lower(l_user) ))
OR (fp.RESP3 in (select f.RESP from FORM f
left outer join RESPONSIBLE3 e on e.RESP3=f.RESP3
left outer join USERS u on u.ID=e.ID where lower(u.USERNAME) =lower(l_user) ));
return APEX_PAGE.GET_URL(p_page =>l_branch_page);
exception
when no_data_found then
/*Use current page as default page*/
return APEX_PAGE.GET_URL(p_page =>1);
end ;
I then call this function in a pl/sql process when the button NEXT is clicked.
DECLARE
x varchar2(4000);
BEGIN
x:=forward_user(:session_user_name);
END;
I have already checked the sql statements and they work fine, I get the corresponding page.
As well the function compiles successfully.
But when I click the button nothing happens, the user is not forwarded to the stored page in the table.
As well I tried to call this function in a branching process with the behaviour Function Returning a URL(Redirect) but as well nothing happens.
Can someone help me here?
My suggestion would be:
create a hidden page item (as you're on Page 1, let's call it P1_URL)
you already have a process which runs when the Submit button is pressed. Its execution point should be "Processing". Rewrite the process so that it populates P1_URL, e.g.
declare
l_branch_page number;
begin
-- your query goes here; I'll redirect to page 4
l_branch_page := 4;
:P1_URL := APEX_PAGE.GET_URL(p_page => l_branch_page);
end;
create an After Processing branch (why? So that process (see above) first populates P1_URL item). Its behavior's type should be "Page or URL (Redirect)", and its target should be &P1_URL. (literally that - ampersand followed by P1_URL followed by dot).
That's all; when you push the Submit button, process will populate P1_URL item which will be used by the branch and redirect to desired page. Will it work? It worked for me, I've just tested it.
Function:
function forward_user (p_username in varchar2)
return varchar2
is
...
return apex_page.get_url(p_page => l_branch_page);
end;
Process: just one line:
:P1_URL := forward_user(:session_user_name);
I want to call validation when
query return at least one row like ( select 1 from table where id = 1 )
and
when request "add_data" is called
Don't know what to select here:
The value of request can be accessed via the bind variable REQUEST . To tackle your specific problem you could add that to your condition of type 'Rows returned' like this:
SELECT 1
FROM table
WHERE (
id = 1 AND
:REQUEST = 'add_data'
)
If you're more a fan of pl/sql you could take the condition type 'PL/SQL Function Body' with code like this:
DECLARE
l_dummy NUMBER;
BEGIN
-- quit here if request value doesn't match
IF :REQUEST != 'add_data' THEN
RETURN false;
END IF;
-- check if we have rows in table.
BEGIN
SELECT 1
INTO l_dummy
WHERE EXISTS (select 1 from table where id = 1)
EXCEPTION WHEN NO_DATA_FOUND THEN
RETURN false;
END;
RETURN true;
END;
This is more code but you could find it easier to read which can be an advantage for maintenance later on.
The way I understood it, add_data request is related to a button you push. If that's so, then - if you don't do anything, request name equals button name - so let's pretend that button name is ADD_DATA. Therefore:
in "When Button Pressed" property select button's name (ADD_DATA, right?)
in "Condition Type" pick the condition you mentioned ("SQL query returns at least one row")
In validation's PL/SQL,is there any way to get the status of a given page item to know if it is changed. Similar to the one in JS API, apex.item.isChanged()?
In the session information (accessed from the developer tools) we can see the status as "Updated" for page Items changed after rendering. How can we get that in the PLSQL in validations?
Any help would be appreciated.
Thanks
if it is a database item, could you select it from the db and compare it to the value on the page? something like :
declare
value varchar2(250);
begin
select your_column into value from your_table where id = :PAGE_ITEM_ID;
if value != :PAGE_ITEM_VALUE then
/*do _something_here*/
end if;
end;
I modified the procedure to make it smaller but I really only want to run the select query once. This will reduce the cost of running the procedure. How can I get the prevContectID and nextContentID without running the query twice. This is replacing a previous procedure so I do not want to change the IN and OUT so I do not have to find every where it is being called.
procedure getSeq(theContentID IN table.contentID%type,
prevContentID OUT table.contentID%type,
nextContentID OUT table.contentID%type)
BEGIN
SELECT myPrev into prevContentID, myNext into nextContentID
from myTable
where contentID=theContentID;
RETURN;
END getSeq;
The shown procedure most likely doesn't compile. The correct syntax for SELECT ... INTO using several variables is:
SELECT myPrev, myNext INTO prevContentID, nextContentID
from myTable
where contentID = theContentID;
You can also use a cursor to fetch the values from myTable.For your approach you need to do proper exception handling ,when theContentID does not exists in myTable,because that will give you NO_DATA_FOUND exception.
PROCEDURE getSeq (theContentID IN table.contentID%TYPE,
prevContentID OUT table.contentID%TYPE,
nextContentID OUT table.contentID%TYPE)
IS
CURSOR getcontentID_cur
IS
SELECT myPrev, myNext
FROM myTable
WHERE contentID = theContentID;
BEGIN
OPEN getcontentID_cur;
FETCH getcontentID_cur
INTO prevContentID, nextContentID;
CLOSE getcontentID_cur;
END getSeq;
I have a form field where one of the values has a default value defined in a an application settings table. The user would see the default value upon display of the create form, but could change it to another value if they wanted prior to saving the new row.
I don't see any way in the field defaults to specify that the default value is the result of an SQL query (e.g. select default_rate from app_defaults where row_key = 1).
Surely this has to be possible, but how?
As posted to Jeffrey above, final solution can be done completely within APEX but using the Default Value Type = PL/SQL Function Body on the page item.
DECLARE default_value number(9,2);
BEGIN
SELECT deflt_rate INTO default_value FROM app_defaults WHERE row_key = 1;
RETURN default_value;
END;
You can use the SQL query in a PL/SQL block to assign it directly, e.g.
SELECT default_rate
INTO :myblock.rate
FROM app_defaults
WHERE row_key = 1;