Open ariroffe opened 1 year ago
I believe you should be able to do that with a route pre-condition: https://github.com/ItalyPaleAle/svelte-spa-router/blob/master/Advanced%20Usage.md#route-pre-conditions
Hi, I'm also currently trying to implement a confirm dialog with pre-conditions. A problem I came across thereby is that an empty page is loaded when the pre-conditions fail. To circumvent this, I've tried to use on:conditionsFailed
to manually set the location back to the original page (using replace
or pop
), but this leads to the component being reloaded, which is a problem in my use case. Would you happen to know if there's a way to stay on the same page and not reload it when a pre-condition fails?
I don't believe that's possible at this time. Perhaps it could be done by creating another hook that is executed before the route is un-mounted.
Thank you very much for your reply. You mean kinda like an exit-conditions
counterpart to pre-conditions
that would check registered conditions before leaving a route?
I can try to implement such a functionality analogously to how pre-conditions are implemented, if you think that that would be a good addition. :)
plus one for this. looking to have a user confirm exiting with unsaved data before navigation. reloading the existing route on failure of a route guard would cause the form state to be lost. 😞 @davidd7 did you ever find a workaround?
<script lang="ts">
import { get } from "svelte/store";
import { link, location } from "svelte-spa-router";
import { confirmNavigation, dirty } from "@/lib/stores/ui";
function checkLink(node: HTMLAnchorElement, params: any) {
node.addEventListener("click", check);
async function check(e: MouseEvent) {
if (get(dirty)) {
e.preventDefault();
e.stopImmediatePropagation();
const response = await new Promise((r) => {
confirmNavigation.set(r);
});
confirmNavigation.set(undefined);
if (response) {
dirty.set(false);
window.location.hash = node.getAttribute("href") || "";
}
}
}
const { update } = link(node, params);
return {
update,
destroy() {
node.removeEventListener("click", check);
},
};
}
</script>
<a ... use:checkLink>
<slot/>
</a>
This is a global link component with a use directive that bails out on certain conditions ... it runs the svelte-spa-router link directive to maintain functionality. It then sets a writable with the resolve method of a promise. if that promise resolves to true
it tries to mimic the functionality of the link directive (which is a fancy way of saying that it updates the hash) save for the scroll linking which was not needed in my case. if it resolves to false
it just clears the writable value and exits. elsewhere in the app, like a confirmation dialog, the writable can be called thusly:
$confirmNavigation?.(true | false);
Hope this helps someone looking for a workaround to this! I explored the option suggested above and realized that an exit route guard would be tricky because the hash updates independently of the route logic. so it could get messy figuring out if the outgoing route has exit conditions that fail and reverting the hash. This seems easier for now.
push
/replace
/pop
/etc could be shimmed in a similar manner, i just don't have that use case.onbeforeunload
behavior, as browser native navigations would circumvent this check. but i suspect that would be trickier to implement.
Hi, thank you for creating and maintaining this package!
I need to show a confirmation dialog before a user leaves a specific route, and call a function if she decides to leave. I can use
window.onbeforeunload
to handle cases where, for example, the user just navigates to a diferent site.But
beforeunload
does not fire if the user manually enters a different route within the same spa (one that is still prefixed with#
) in the address bar, or, e.g., if she presses the back button.I've tried asking for confirmation in the route's associated component
onDestroy
method, but I couldn't find a way to stop the component's destruction afterwards. Even if I raise an error, the component remains on the page but the url still changes.Is there any way of doing this with
svelte-spa-router
?