Dash Callback on Page Exit

Hi!

I am currently developing an app using Dash Python that has users upload files that will then be placed in an app directory for temporary storage to be used for visualization in a callback. After the callback, the files are then deleted.
The issue is that there may be instances in which the files may still linger, whether that may be through an interruption before the callback, the user exits the page preemptively, etc. In order to alleviate this issue, I was thinking that I would keep a record of all paths created and then have the app just shutil.rmtree all these paths upon the user exiting the app.
I have tried searching through the internet, but can’t seem to find information about this type of capability existing. Is it possible to have a callback be run upon a user exiting the webpage/refreshing the webpage?

Thank you!

Hello @hypervalent,

Welcome to the community!

You are looking for a combo, a window listener on JavaScript that on beforeunload clicks a button that triggers your callback.

1 Like

Thanks for the warm welcome @jinnyzor !

This is exactly what I am looking for thank you!
I’m just confused on how I would go about implementing this, as it seems this is an HTML/JS component rather than a Dash Python component. Would I need to make a separate JS file for this? Or is there a way to implement it into app.py?

1 Like

Yes, it is a separate component not in the Dash app. It needs to be a separate file.

Make a folder called assets in the same directory as the app, things in this folder will auto load to the site.

1 Like

Hey @jinnyzor

Sorry for the late response!
The solution to use a separate JS file in the ‘assets’ directory raises another question for me.
All the history of directories/files to be deleted through this onbeforeunload event are being logged as a list by a html.Div component in Dash, as having separate users using the app at once would mean personalized logs would be useful.
Is there a way for this JS file to get the children from this html.Div component? Assuming that the JS file containing the onbeforeunload event is coded as follows:

<!DOCTYPE html>
<html>
<body onbeforeunload="return myFunction()">
    
<script>
function myFunction() {
  /// Take list from children of html.Div and delete files by iterating through this list
}
</script>

</body>
</html>

Thank you!

Not entirely sure what you mean by this…

Yes, javascript is able to remove all the elements from a layout: $('body').empty() would remove all the children.

You are trying to log what specific interactions with the user? Custom layouts can be save utilizing authentication if necessary.

Ah sorry, I should have explained better.

So basically I have an html.Div component that logs all the files/directories that are created by the user during their session. For example, if we have files with paths: file1.txt, file2.txt, file3.txt, then the html.Div component would contain the string representation of this list of files: “[file1.txt, file2.txt, file3.txt]”.
In this case, I was hoping that the onbeforeunload event would be able to pull this list from the html.Div and iterate through it in order to purge the files on unload.

Yes.

However, since this is more than likely stored on the server side, your onbeforeunload would have to fire an event (clicking a button is easy) and trigger the callback on the server with the children of that div as a state, and then you could remove all of those files that way.

I’m sorry it is now my turn to say I’m not entirely sure what you mean by this.

So you are saying that it is not possible to pass the children of the div as a state without using a Dash callback? Would this not work if the user unloads the session by exiting or refreshing the webpage without clicking the specific button to trigger the callback?

You are asking to be notified when the browser closes, this requires an event listener on the client.

You are wanting to use this to dump the user’s data from your server’s file system (correct?) In order to do so, you’d have to have something that triggers it to do so. An invisible button that gets triggered from the onbeforeunload like this:

document.addEventListener("onbeforeunload", function() {document.getElementById('hiddenButton').dispatchEvent(new Event("click")})

If you are talking about removing elements after close, the system will automatically do that, because it is a new session.

Ah I see what you mean.

So as long as I just put that one line of code into a JS file in the ‘assets’ directory, it will call the callback associated with this hidden button?

1 Like