Show an animated “Please wait” indicator after page submit
My application normally responds to button clicks with sub-second performance, but there were a few operations where users can initiate quite long-running transactions (e.g. up to 15 seconds long in one case where it was hitting an eBus interface thousands of times).
When the user clicks the button, I want the page to show a “Please Wait” message with an animated running indicator (I won’t call it a “progress bar” even though it looks like one, because it doesn’t really show progress, it just rotates forever) until the page request returns.
To do this I added the following to my application, based largely on this helpful article.
1. Add an HTML region on Page 0 (so it gets rendered on every page) at Before Footer, with:
<div id="runningindicator"> Processing, please wait... <div id="runningindicator-img"></div> </div>
2. Add the following to the global CSS file for my application:
div#runningindicator { display: none; background-color: #FFF; padding: 30px; border: 1px solid; border-color: #CCC; box-shadow: 2px 2px 2px #AAA; border-radius: 4px; position: absolute; top: 100px; left: 50%; margin-left: -110px; /* the half of the width */ } div#runningindicator-img { background-image: url(/i/processing3.gif); background-repeat: no-repeat; width: 220px; /* the exact width of the image */ height: 19px; /* the exact height of the image */ }
3. Add the following to the global javascript file for my application:
function run_long_request (request, warnmsg) { if (!warnmsg || confirm(warnmsg)) { // disable all buttons on the page var btns = $("a[role='button']"); $x_disableItem(btns, true); $("div#runningindicator").show(); apex.submit(request); } }
4. Change the button:
Action = Redirect to URL
URL Target =
javascript:run_long_request('APPROVE', 'Are you sure you wish to approve this transaction?');
When clicked, the button runs my javascript function which first prompts the user to confirm, and if they do, it disables all the buttons on the page, shows the running indicator, and submits the request (which might be the name of the button, for example).
If I omit the second parameter, the function skips the confirm popup and submits straight away.
Known Issue: the animated gif doesn’t seem to animate in IE8. So far I haven’t worked out how to solve this, except to burn IE8 with fire and extreme prejudice. I’ve tried using setTimeout to delay showing the div but it stubbornly stays frozen.
EDIT: thanks to Peter Raganitsch who alerted me to a simpler option, that doesn’t need the region or the CSS, and animates in IE8:
function run_long_request (request, warnmsg) { if (!warnmsg || confirm(warnmsg)) { apex.submit({request:request,showWait:true}); } }
Mind you, building this sort of thing from scratch was a useful exercise to learn the CSS and javascript tricks necessary. And another thing re-learned: there’s almost always a simpler way.
Amol
5 April 2018 - 2:15 pm
Hi Jeff,
I appreciate your efforts to sharing useful code globally.
I have one doubt .how to display show-wait on ajax call which would not need to submit page. Any suggestion?
Jeffrey Kemp
17 April 2018 - 12:54 pm
Hi Amol,
You can show the spinner in javascript (e.g. as one of your dynamic action steps) using apex.util.showSpinner.
To show the spinner:
lSpinner$ = apex.util.showSpinner( $( "#container_id" ) );
To remove the spinner:
lSpinner$.remove();
If I were to put the above code in a dynamic action, I’d put the following declaration in the page’s Function and Global Variable Declaration property:
var lSpinner$;
Reference:
https://docs.oracle.com/database/apex-5.1/AEAPI/apex-util-namespace.htm#AEAPI30161
I hope this helps.
Martin Rose
23 July 2018 - 6:25 pm
That’s fine Jeff. But apex.util.showSpinner doesn’t show when you have a PL/SQL process in the middle of a DA until the end of the DA.
Ie; Step 1 – apex.util.showSpinner
Step 2 – Long-running PL/SQL
Step 3 – Remove spinner
The spinner won’t show until AFTER step 2, which ofc then gets immediately removed as that’s the next instruction. I want it to show at step 1, before step 2 starts.
Jeffrey Kemp
24 July 2018 - 2:08 pm
Hi Martin,
Thanks for your comment, that’s correct it doesn’t work if the dynamic action is a PL/SQL call.
Options to workaround this limitation include changing it to use a Submit action (described here: https://community.oracle.com/thread/4132363 in a comment from Mint-Innit), or to use apex.server.process instead to run the PL/SQL.
For more reading on this I’d refer you to this article: http://www.grassroots-oracle.com/2016/06/synchronous-dynamic-actions-in-apex-51.html
I hope this helps,
Jeff
Nikita Kochar
21 July 2019 - 11:21 pm
Hi Jeff,
Thanks for the code.. But I would like to know how can we replicate the same functionality on form load? My Apex application form is being invoked by some other application(non apex). Please guide.
Jeffrey Kemp
21 July 2019 - 11:41 pm
Hi Nikita, that’s a good question. If your page takes a long time to load, your code won’t run until it’s fully loaded; so to show the spinner I think you may need to move the bulk of the workload to a separate ajax call (using a Dynamic Action that runs on Page Load).
Nikita Kochar
22 July 2019 - 10:24 pm
Hi Jeff,
Actually, there is a non apex application that is writing data into my oracle database and invoking my apex application to see the newly written data. Now the problem is, it is taking about 6-10 seconds for the non apex app to write data into my database. So when it invokes my apex app, the page report shows no data found error and after a few seconds, when I reload the page, it shows the data successfully. So this is due to latency in writing data into my apex app. Hence, I want to show a spinner for 6-10 seconds when the page is invoked so that this time will be consumed to write data into DB and after 6-10 seconds, the page must show the data. I am using Apex 4.2. Please help
Jeffrey Kemp
22 July 2019 - 10:39 pm
Hi Nikita,
You could show a “Loading, please wait” message with a condition based on “No Rows Returned” from your query.
You could use something like this tip to have the page refresh every few seconds until the data is loaded:
https://jeffkemponoracle.com/2006/10/apex-tip-page-auto-refresh/
I hope this helps.
Nikita Kochar
22 July 2019 - 11:00 pm
Hi Jeff,
Thanks alot for your help!!
I tried to auto refresh after 5 seconds interval.. But I need to do this refresh activity only once because anyhow, my data gets loaded in that amount of time.
Also need your help to understand, where(event) should I write the SQL query to check my DB?
Jeffrey Kemp
23 July 2019 - 6:52 pm
Hi Nikita,
To refresh a report, you add a “Refresh” dynamic action to your page. That’s all you need.
The tricky part is delaying it for a set interval. To do this you need to run some custom javascript:
setTimeout(function() {apex.region("myRegionId".refresh()}, 6000);
In the call above, 6000 means “wait for 6 seconds”. Whatever appears within the function will be executed after that time.
You will need to set a static ID on the report region, e.g. myRegionId.
Nikita
6 August 2019 - 8:41 pm
Hi Jeff,
Thanks for the help.. It works fine now.. But there is an additional requirement in the code, where in the page should run the dynamic action to show the progress bar only 3 times. After which it should move to the error page saying record not loaded.. how do I achieve that
Fahad
29 May 2022 - 5:43 am
is there any way to remove spinner dynamically instead of putting seconds?
setTimeout(function() {apex.region(“myRegionId”.refresh()}, 6000);
Jeffrey Kemp
30 May 2022 - 2:20 pm
Hi Fahad,
Yes, if you create a Dynamic Action that fires when the event you specify occurs.