Trigger a process (SQL update) when leaving an APEX page - oracle-apex

This is a very odd question but i wondered whether it was possible to trigger a process that runs an SQL UPDATE when the user leaves this specific page, either by clicking on the breadcrumb, tabs or back button?
I did setup the process to run on the 'Back' button; however i ran into the problem of: What if s/he clicks on the breadcrumb or a tab instead.
I have searched the net and posting this question was a last resort. I wondered if anyone can point me in the correct direction?
UPDATED POST
Page 1:
Includes a text field and a button. The user enters the category into the text field and clicks on the button to proceed to the next page. The button passes the value in the text field to a text field on Page 2.
Page 2:
Two regions on the page. One region holds information about the category - Category name from the previous page, category description, and the category revision number (which is what i'm trying to get working). The second region is a report that pulls the item name and number that are listed under the category in the category text field. A 'View' link is used on the report to load the edit page for the specific item selected. The 'View' link passes the 'category name' (from the category text field) and the 'item number' from the report to page 3.
Page 3
Two regions are used, first region: Lists the Item number which came from page 2 and name of the item (which i use a simple query to retrieve). In the second region: A report is used with two columns: a list of item properties in column 1, and a text field next to each item property in column 2 to hold the value that can be updated. The 'Apply Changes' button has some PlSql behind which looks for changes and updates where required. It updates the relevant fields that have changed, and it then takes the user back to Page 2 (Page showing user the items listed for the category intitally entered).
I cant increase the category revision on the 'apply changes' button on page 3 because the user may complete edits for items under the same category. So i dont know where i can increase the category revision by 1 per vist to a category. P.s I already increment the revision number for each item by 1 if the info has been changed using the 'apply changes' button on page 3.

One way of doing this is by updating the session state of the page items (without submitting the page as normal) via ajax and by calling an Application Process which updates the table, when called by a javascript onbeforeunload.
Create an Application Process to fire On Demand, named UpdatePageXOnExit or something. In the PL/SQL block of that Application Process, use SQL update commands with the item state of each item on the page that you wish to update; something like the following:
BEGIN
UPDATE table_name SET col1 = :PX_ITEM_1, col2 = :PX_ITEM_2, col3 = :PX_ITEM3, col4 = :PX_ITEM_4, col5 = PX_ITEM_5
WHERE (condition... I would suggest ROWIDs to simplify changes to the
fields of the PK; otherwise you will have to create additional
page items for each field of the PK, then set those items to
the values of the PK when the page loads using a before
header page process, and then use those values in this where
clause like this: where col1 = :PX_ORIGINAL_PK_FIELD_1 AND col2 =
:PX_ORIGINAL_PK_FIELD_2 );
END ;
Go to the page settings for that particular page, and in the JavaScript: Execute On Page Load section, write something like the following:
window.onbeforeunload = updateOnExit;
And in the JavaScript Function and Global Variables Declaration, write something like the following:
function updateOnExit() {
var get = new htmldb_Get(null,&APP_ID.,'APPLICATION_PROCESS=UpdatePageXOnExit',&APP_PAGE_ID.);
get.add('PX_ITEM_1',$x('PX_ITEM_1').value)
get.add('PX_ITEM_2',$x('PX_ITEM_2').value)
get.add('PX_ITEM_3',$x('PX_ITEM_3').value)
get.add('PX_ITEM_4',$x('PX_ITEM_4').value)
get.add('PX_ITEM_5',$x('PX_ITEM_5').value)
gReturn = get.get();
get = null;
// Comment out the following line or not, as per the note in the following paragraph
return 'Are you sure you would like to leave the page?';
}
This last piece is the AJAX that updates the session states of the page items on the page that have been changed on the user's end but that haven't been uploaded to the servers end which normally occurs during page submission. Note: If you comment out the return statement, than there will be no warning box that will allow the user to stay on the page. If that is what you prefer, go for it. If you chose to use the warning box, the ajax will execute the page process even if the user chooses to stay on the page.

Related

Oracle Apex: How i can make page item Display Only while can still be updated through Dynamic Action

have a page with some page items (region on top of page) and an interactive grid below it. one of page item have sum of an ig column, another page item is Discount, after user enter any discount amount, there are more 2 columns updated/calculated with Dynamic Actions. how i can prevent user interaction with those page items except Discount which required to.
you can use custom css class to that item and inline css for display only, or you can use custom attribute to item as disabled.
You can check afterwards on browser console on dom if it is on the correct level of the page item.
For example I have a textfield item on the page:
if I use staticid or id that is generated by the Oracle Apex and on the page's execute when page load section:
$('#P30_ORDERNR').attr('disabled');
this will add disabled attribute to my item which means it can be set but not by user.

Oracle Apex Dynamic action not working for form items

I have a form with items P1_APP and P1_USER.
P.S. P1_USER is select list.
Display John
Return 1
Display Andy
Return 2
I need to disable when user selects John.
When P1_USER = 'John', P1_APP should get disabled which is a multi select list.
I created dynamic action on P1_APP, True Action= Disable,Affected element P1_APP
Client condition : Item =Value
Item= P1_USER
Value= John
However this is not working.
I have used similar logic to disable interactive grid items and was able to do so. Why is this not working for form?
EDIT: In Value now i am putting 1 which is return value for John.
However when i select John. It disables P1_App upon clicking. But remains disabled even when i choose Andy.
This works for me using the following configuration.
Create form and report on EMP - everyone has access to that sample data, it is a good idea to post questions based on that.
In the form P3_DEPTNO is a select list with source
SELECT d.dname, d.deptno FROM dept d
Add a page item to my form P3_APP. This is a select list with "Allow multi selection" enabled. Select list has 2 static values.
Create a dynamic action on change of P3_DEPTNO.
Client side condition: Item = Value
Item: P3_DEPTNO
Value: 30 (note that this is the return value for SALES, not display value)
add true action of "Disable", affected item P3_APP
Click true action and select "Create Opposite Action". Save.
When I run this it work. Selecting SALES in the select list disables the item P3_APP and selecting something else enables it.

How I can make Mandatory add at least one row in Interactive grid in apex oracle

I have two region one form and one interactive grid like a master detail(company and company contact person ) how i can make the interactive grid mandatory ,the user can't submit page ,he/she need add at least one row in interactive grid ,
I can do that or I need to change the interactive grid to collection and count the row in validation
This one is a little tricky because of the way processes and validations work with Interactive Grids (they are executed once per submitted row). To work around this, I'll use a page item and a validation that works with it.
The basic idea of this solution is based on the fact that a new row will not have a primary key value. Here are the steps to reproduce (my example was on page 14, update the following as needed).
Create an Interactive Grid (IG) region. The primary key column should be Query Only (which ensures it's null for new rows).
Create a Hidden page item named P14_NULL_FOUND. Set Type under Server-side Condition to Never so that it never renders on the page.
Create an After Submit (before Validations) process. This process will NOT be associated with the IG so it will only fire once. Set the PL/SQL Code attribute to:
:P14_NULL_FOUND := 'NO';
That will clear out the value of the page item prior to the next process.
Create another After Submit process that runs just after the previous one. Set Editable Region to the IG. Then set the PL/SQL Code to something like the following:
if :PK_COLUMN_IN_IG is null
then
:P14_NULL_FOUND := 'YES';
end if;
You'll need to replace ":PK_COLUMN_IN_IG" with the name of the primary key column in the IG, such as ":EMPNO". This process will be run once for each submitted row in the IG. If a null value is found for the primary key column, then that would mean the user added a new row and the value of P14_NULL_FOUND would be set to 'YES'.
Create a new validation. This validation will NOT be associated with the IG so it will only fire once. Set Type to PL/SQL Expression. Set PL/SQL Expression to:
:P14_NULL_FOUND != 'NO'
Then set Error Message to something relevant.
At this point, you should be able to run the page and verify that the processes and validation are working correctly.
There is an another solution;
Create a page item like PX_ROWCOUNT which will hold the data of the row count of your IG.
Assign a static ID to your IG region.
Write a JS function to count the rows of the grid then set it to the page item. Sample function;
function f_setRowCount(){
var grid = apex.region("staticIDOfYourIG").widget().interactiveGrid("getViews", "grid");
var model = grid.model;
var rowCount = 0;
model.forEach(function (record) {
rowCount ++;
});
$s("PX_ROWCOUNT",rowCount);
}
To submit your page and run this function, change your submit button's behavior to Defined by Dynamic Action. Execute your function when user clicks to that button then submit your page via DA.
Add validation to Processing section of the page and check your page item there; PLSQL Expression => :PX_ROWCOUNT > 0
The solution by Hamit works nicely, except of the case of deletion of a row.
My suggestion is to amend the above code by adding inside the loop an if statement to check whether the row is editable or no.
So the code will be
var grid = apex.region("staticIDOfYourIG").widget().interactiveGrid("getViews", "grid");
var model = grid.model;
var rowCount = 0;
model.forEach(function (record) {
if (model.allowEdit(record)) {
rowCount ++;
}
});
$s("PX_ROWCOUNT",rowCount);

How to save and return to newly created item in previous page?

I have an interactive report and a form associated to it. After creating a new entry using the form, my end-users want to put the focus on that specific new entry in the interactive report (it's a lot of entrys, and today they need to scroll down a lot to see the new one).
They also want the same funcionality when updating a row of the report.
How can I do this the correct way in APEX 5.1?
Here is one aproach based on EMP table in apex.oracle.com Create interactive report with edit form. In my case this is page 6 for report and page 7 for edit. Create one hiden item on page six (P6_EMPNO). Add case to your query so in my example it's look something like:
select "ROWID",
"EMPNO",
"ENAME",
"JOB",
"MGR",
"HIREDATE",
"SAL",
"COMM",
"DEPTNO"
from "#OWNER#"."EMP"
ORDER BY CASE WHEN EMPNO = :P6_EMPNO THEN 1 ELSE 2 END, EMPNO
I'm sorting result by EMPNO.
Choose P6_EMPNO in Page Items to Submit section. Go to page 7, select branch(Go to page 6)and click on Target In set items section choose P6_EMPNO and for target &P7_EMPNO.
Now every time you go to page 7, the value of hiden item will be the EMPNO from page 7 and it will apear on top of the region. You can use jQuery to highlight the row and put some validations to update P6_EMPNO only when some data was changed.
I hope this can help you.
easy.
You don't even have to create any additional page items. Change your form DML so that it returns into the primary key page item holder. Then Create a process after your DML process but before the reset cache process. Use APEX_IR API to reset pagination on your IR page, and then set an interactive report filter based on the primary key page item you returned the new PK into. Check the documentation for exact usage.
Apex_IR.reset_report to reset the report pagination and remove any filters.
Apex_ir.add_filter to add a filter = to new primary key
Interesting question, another solution:
Create a item in your report page, something like P3_ANCHOR
Add data-anchor="#< YOUR_COLUMN_ID >#" to your report link attribute
Configure your form page to return the created/modified item id to item P3_ANCHOR in your report page.
Create a Dynamic Action on report page
Action: Execute Javascript Code
Code:
var container = $('body'),
scrollTo = $('[data-anchor="'+$v('P3_ANCHOR')+'"]');
container.animate({
scrollTop: scrollTo.offset().top - $(document).scrollTop()
}, 2000);
Simple solution:
Sort your report descending so that the last created ID will be the first in the IR

APEX: Item is blank when trying to prepopulate with value

My Scenario:
I have a report on page 1 which has a link to page 2. This link passes an ID to page 2 (V2_ID gets set with V1_ID).
I then have two items called V2_ID and V2_NAME on page 2, as well as a PL/SQL process on page 2 which executes after the header loads which
select name into :V2_NAME from table where id = :V_ID;
The V2_ID shows the value, but the V2_NAME is always blank.
How can I pre-populate this variable. This is a very simple example as my use case is much more complicated, but the concept is the same. I can't use automatic row fetch because each item comes from a different table (it is a horrible database design, but I have to work with it).
Cheers
If on page 2 you have a PL/SQL process at the process point='On Load - After Header' and the procedure looks something like this:
Begin
select name into :V2_NAME from table where id =:V2_ID;
end;
and no condition on it then it should work.
Check that :V2_NAME does not have Source Type= Always NULL;
Correct me if Im wrong, from what ive understood, only one value is passed from page 1 to page 2 which is V1_ID to V2_ID,right?then on page 2, you have a process that will execute after the header loads and that is
SELECT name
INTO :V2_NAME
FROM TABLE
WHERE id = :V_ID
Is the :V_ID a typo?It should be :V2_ID,if its not maybe its the cause as to why :V2_NAME doesnt give you a value.
Instead of having a process after header, why dont you just put the query in the item SOURCE, choose type: QUERY, used: ALWAYS, REPLACE ANY EXISTING VALUES ON SESSION STATE.
then in the query box, put
SELECT name
FROM TABLE
WHERE id = :V2_ID