I am building my first web app using Flask. I'm new to html/ JavaScript/ CSS - please bear with me.
The app does the following: The user uploads an Excel file as follows:
<form method="POST" enctype="multipart/form-data">
<input type="file" name="file" id="file" />
Then they select certain parameters using dropdown lists. When the user clicks "Submit", the data is manipulated using pandas and a new file is exported in Excel.
I managed to add a spinner to the "submit" button using html and CSS. I added an event listener to my JavaScript so the spinner is activated when the button is clicked. At the moment, the spinner runs indefinitely, however I would like the spinner to stop and the button text to revert to "submit" once the operation is finished, i.e. the export is complete. Does anybody know how I can accomplish this?
Here is my html:
<button type="submit" id="submit" class="button">
<span class="button__text">Submit</span>
</button>
Here is my CSS:
<style>
.button {
position: relative;
padding: 8px 16px;
background: #009579;
border: none;
outline: none;
border-radius: 2px;
cursor: pointer;
}
.button:active {
background: #007a63;
}
.button__text {
font: bold 20px "Quicksand", san-serif;
color: #ffffff;
transition: all 0.2s;
}
.button--loading .button__text {
visibility: hidden;
opacity: 0;
}
.button--loading::after {
content: "";
position: absolute;
width: 16px;
height: 16px;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
border: 4px solid transparent;
border-top-color: #ffffff;
border-radius: 50%;
animation: button-loading-spinner 1s ease infinite;
}
/*animate spinner - spin from 0 to 1 turn*/
@keyframes button-loading-spinner {
from {
transform: rotate(0turn);
}
to {
transform: rotate(1turn);
}
</style>
Here is my JavaScript:
<script type="text/javascript">
(() => {
const elem = document.getElementById('submit');
elem.disabled = false;
elem.addEventListener('click', e=> {
elem.classList.add('button--loading');
});
})();
</script>
Basically, your frontend (the HTML/Javascript) needs some way of knowing when "the export is complete". Depending on your definition of "export" and "complete".
At the most rudimentary level, you could have the frontend poll the server every second after the upload starts, and have the server return some kind of status as to what the state of the process is. This could be as simple as:
GET /status/1234
> {"status": "IN_PROGRESS"}
which, when the "export is complete" switches to:
> {"status": "COMPLETE"}
And when the frontend receives the COMPLETE status, it removes the spinner. Notice the 1234. You will need some way of identifying the upload in progress. One way to do this would be to assign it a random id when you first accept the form, so the initial POST /upload returns > {'id': 1234} which the client can then use for the subsequent polling.
If "export is complete" actually only means that the file is finished uploading, you could still use a polling method, but a much slicker way is to use the client (web browser) method of determining how many bytes have been sent (see this SO answer).