APEX spinner download indicator using Vanilla JavaScript (async/await)

There are plenty of good resources explaining how to create custom download links in APEX so I will skip over that part and list a couple here:
- https://oracle-base.com/articles/misc/apex-tips-file-download-from-a-button-or-link
- https://joelkallman.blogspot.com/2014/03/yet-another-post-how-to-link-to.html
These examples go into good detail on how to generate a custom link to download a file. But what about how to indicate that a file is downloading if it is taking a long time in the backend?
Problem
Some custom download processes can take quite sometime depending on what the process is doing in the backend (generation/business logic). It can be quite confusing to the end user that a process is occurring and for them to even know that they are waiting on downloading a file at all if this is the case.
If it takes a long time to run the process that ultimately downloads the file - then just setting a spinner on page submit or via apex.server.process will not necessarily achieve the desired outcome. Usually the apex engine is killed when you dedicate a page/process to download the file, and subsequently you can not easily signal that the download process is done and to take action upon that to kill a spinner if you had one going.
There are a few plugins out there that you can use in combination with each other as well. Lets just assume that you have a link already set up to download your file and that it kicks off some custom process to do so. Here is a quick Vanilla JavaScript approach to achieve a spinner while the download process is occurring and to remove it when it is done.
Solution
- Declare the following download function:

Page Properties -> Function and Global Variable Declaration
const download = async (url, filename) => {
// add spinner
var lSpinner$ = apex.util.showSpinner();
const data = await fetch(url);
const blob = await data.blob();
const objectUrl = URL.createObjectURL(blob);
const link = document.createElement("a");
// set link download url/filename
link.setAttribute("href", objectUrl);
link.setAttribute("download", filename);
link.style.display = "none";
// add link and download file
document.body.appendChild(link);
link.click();
URL.revokeObjectURL(blob);
link.remove();
// remove spinner
lSpinner$.remove();
};
This is utilizing async and await to make us wait for the promise to return a result. Majority of the waiting done is on the fetch here in my case as my process running takes over 5 seconds before it even sends a file back to the client. This allows us to confidently set a spinner before we wait for the result, and then remove the spinner after all of our code is done running.
2. Declare a Dynamic Action on button click to download the file

Dynamic Action -> Code
My download link runs a process that takes over 5 seconds to generate my file. I am using page items to hold the url and filename, so I used this:
download(apex.items.P1_DOWNLOAD_URL.value, apex.items.P1_FILENAME.value)

That is it. This concept can be used also to fire other events after a custom file generation process is done as well and not just to get a spinner. Hope this helps any of you that have long running download processes so that the end user is aware that something is occurring. Cheers!
Comments
Join the discussionNo comments yet. Be the first to comment.



