We're trying to implement a "Leave site? Changes you made may not be saved." prompt. Everything is working nicely with these changes:
app.js
let Hooks = {};
Hooks.BeforeUnload = {
hasChanged() {
return this.el.dataset.hasChanged === "true";
},
mounted() {
window.addEventListener("beforeunload", e => {
if (this.hasChanged()) {
e.preventDefault();
e.returnValue = "";
}
});
}
};
let liveSocket = new LiveSocket("/live", Socket, { hooks: Hooks });
form.html.leex
<%= f =
form_for(@changeset, "#",
phx_change: :changed,
phx_submit: :submitted,
phx_hook: "BeforeUnload",
data: [has_changed: !Enum.empty?(@changeset.changes)]
) %>
However, when the user cancels the prompt, mount/2 is invoked and the form changes get discarded, which defeats the purpose of the prompt.
The logs show this after canceling the prompt:
[info] CONNECTED TO Phoenix.LiveView.Socket in 260碌s
When the user cancels the prompt, unload event is canceled and the form changes are kept.
Here's a sample repo that reproduces the issue: https://github.com/aptinio/phx_lv_550. I hope this helps.
it happens because Phoenix Socket closes the websocket connection even though the User stays in the page clicking on the cancel button:
I've done some tests and removing that line I got the Hooks.BeforeUnload working as expected. In order to fix that, I think we should somehow check if the user stayed on the page - when he clicks on the cancel button - and don't close the connection.
What about if we use unload instead of beforeunload in order to close the connection? :thinking:I tested it here and it also works, but I'm not sure if that's ok since I'm not familiar with those events.
@chrismccord you might have some thoughts on this since you've introduced this approach on Phoenix channel :raised_hands: :
What about if we use
unloadinstead ofbeforeunloadin order to close the connection?
I thought this doesn't work until I realized I was changing phoenix_live_view.js instead of phoenix.js. :sweat_smile:
I think using unload makes sense. According to MDN:
It is fired after:
beforeunload(cancelable event)pagehideThe document is in the following state:
- All the resources still exist (img, iframe etc.)
- Nothing is visible anymore to the end user
- UI interactions are ineffective (
window.open,alert,confirm, etc.)- An error won't stop the unloading workflow
unload works, but I need to release a new phoenix to make it happen, so stand by for Phoenix v1.4.12 sometime tomorrow. Thanks!
Awesome! Thanks @feliperenan and @chrismccord! :heart:
This has been fixed in Phoenix 1.4.12 and LV 0.6.0. Thanks!