Cancel a click on dcc.Link before Location updates?

I have a multi-page app (with custom pages, pre-2.5). There are some dcc.Link elements there, and a dcc.Location which triggers a callback which in turn changes the layout. Pretty standard stuff I believe.

What I’m trying to implement now is something similar to the browsers “beforeunload” event - so that sometimes (depending on a condition) the app shows a prompt the user to confirm before navigating to another page (or to cancel and stay on the current page).

What would be a good way to achieve this?

1 Like

You might find this post helpful:

That would be for leaving the app altogether. But here I’m interested in preventing navigation to another page within the app.

@frnhr,

The way the app works is navigating to a different url, this is leaving the current page and should trigger as normal. I actually use this event to clear out some localStorage elements that I interact with via Javascript.

Just add your check for if you need to prompt the user before the return statement.

1 Like

Well, not if you use refresh=False in your Location component, which is what the official pre-2.5 example does. And I’m sure the new pages feature does the same.

The beforeunload is triggered only before actually unloading the page.

To clarify, I am looking for a good way of prompting the user when they switch to another page, but without setting refresh=True in dcc.Location component.

This is the official pre-2.5 example linked above, plus a window.onbeforeunload handler. I wish to see the prompt every time the URL changes:

Recording  151

Ooo, ok. That’s fun.

This needs to be used in conjunction with the window.onbeforeunload in order to catch both ways that you could navigate away:

function changeDefaults() {
    console.log('changing defaults')
    $(".ignore-click").click(function() {
        if (confirm('Do you wish to continue?') != true) {
            event.preventDefault();
            event.stopPropagation();
            return false
        }
    })
}

$(document).ready(function() {setTimeout(function(){changeDefaults()},300)})

window.fetch = new Proxy(window.fetch, {
    apply(fetch, that, args) {
        // Forward function call to the original fetch
        const result = fetch.apply(that, args);

        // Do whatever you want with the resulting Promise
        result.then((response) => {
            if (args[0] == '/_dash-update-component') {
                setTimeout(function(){changeDefaults()},300);
            }
        })
        return result;
    }
})

You will also need to add the className=‘ignore-click’ to the links that you want to be effected.

You will also need to load jquery for these functions to work. Straight javascript is a lot more lengthy.

This works, thanks! I was hoping to tap into the URL change mechanism somehow, but hey…

Removed Query and using event delegation instead of the proxy:

document.body.addEventListener('click', (event) => {
    if (event.target.classList.contains('ignore-click')) {
        if (confirm('Do you wish to continue?') != true) {
            event.preventDefault();
            event.stopPropagation();
            return false;
        }
    }
    return true;
});

You could try to listen to the document.location.href / window.location.href for updates.