-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Proposed in #14
Champion
Summary:
usePreventNavigate((url?: URL) => boolean | Promise<boolean>)
What's the motivation for this proposal?
Problems you are trying to solve:
- during filling in a form, waiting for a result etc, the user can inadvertently navigate away, and lose state
Goals you are trying to achieve:
- block navigation when app dirty to prevent data loss
- easy API
Proposed Solution / Feature
What do you propose?
We add usePreventNavigate(cb)
, which registers a handler that will be called when there is a navigation event. When the handler returns true
, navigation is blocked.
This is actually not trivial to implement correctly because not all navigation passes through qwik-city, and when the browser is involved the answer need to be synchronous.
If the navigation attempt is going through qwik-city, the callback will receive the URL of the desired target. This makes it possible to perform the navigation later.
Code examples
using a modal library:
export default component$(() => {
const okToNavigate = useSignal(true);
usePreventNavigate$((url) => {
if (!okToNavigate.value) {
if (!url) return true;
return confirmDialog(
`Do you want to lose changes and go to ${navSig.value}?`
).then(answer => !answer);
}
});
return (
<div>
<button onClick$={() => (okToNavigate.value = !okToNavigate.value)}>
stuff
</button>
<br />
more stuff
</div>
);
});
Using a separate modal:
export default component$(() => {
const okToNavigate = useSignal(true);
const navSig = useSignal<URL | number>();
const showConfirm = useSignal(false);
const nav = useNavigate();
usePreventNavigate$((url) => {
if (!okToNavigate.value) {
if (url) {
navSig.value = url;
showConfirm.value = true;
}
return true;
}
});
return (
<div>
<button onClick$={() => (okToNavigate.value = !okToNavigate.value)}>
stuff
</button>
<br />
more stuff
<br />
{showConfirm.value && (
<div>
<div>
Do you want to lose changes and go to {String(navSig.value)}?
</div>
<button
onClick$={() => {
showConfirm.value = false;
okToNavigate.value = true;
nav(navSig.value!);
}}
>
Yes
</button>
<button onClick$={() => (showConfirm.value = false)}>No</button>
</div>
)}
</div>
);
});
PRs/ Links / References
PRs:
Reference:
Remix Router has useBlocker
, there are interesting tidbits in their decisions document.
christian-unger, AnthonyPAlicea and DustinJSilk
Metadata
Metadata
Assignees
Labels
No labels
Type
Projects
Status
Developer Preview (STAGE 4)