Can you use the vanilla beforeunload?
Detect page refresh/change in Vue
I need to detect a page change or browser refresh in a Vue component. Vue has a beforeDestroyed() method that Ive tried putting on the component, but that doesnt seem to do anything when the page is changed/refreshed. I know you can do this if you use vue router, but this is not a single page app and cant justify pulling in the extra weight for this single feature. Is there another Vue way to do this?
@davestewart That is an option, but it makes it much messier and more complicated. Im not hoping to do an alert box, I want to save a draft of the user input via ajax if they leave the page. I'd really like to keep everything in a component, or at least in Vue, rather than try to tap into the Vue instance via a separate script and send the data that way.
I found this link. http://stackoverflow.com/questions/35816118/vuejs-laravel-do-a-post-request-when-user-leaves-screen
Put the code into my VueJs test app. Could not get beforeunload or onbeforeunload. Quick Google did seem to indicate issues. But onblur works. Here is the snip...
ready: function () {
window.beforeunload = this.leaving;
window.onblur = this.leaving;
//window.onmouseout = this.leaving;
},
methods: {
leaving: function () {
alert("Leaving...");
},
Just a big ugly alert box !
http://stackoverflow.com/questions/13443503/run-javascript-code-on-window-close-or-page-refresh
Gonna look through Vue code a little.
Good Question! Let me know what you find.
I am sure there is a cleaner way. I hate saying things like 'The Vue Way', its library not a mantra...
@zachleigh - it looks like you can make a synchronous ajax call after beforeunload, so that might be an option (a few folks commented against it, but didn't actually reason why):
What about setting a cookie when the user updates the form, and deleting it on submit?
I'd really like to keep everything in a component, or at least in Vue, rather than try to tap into the Vue instance via a separate script and send the data that way.
Well, it's all JavaScript; just put the code where it makes most sense, be it an imported class, Vue ready() method, a Vue directive (maybe on the form), Vue plugin, or even a jQuery plugin if that works. You can always refactor later.
I hate saying things like 'The Vue Way', its library not a mantra...
I hate saying it too, but I've found that usually there is a far better way to do things using built in Vue functionality than my Frankenstein javascript hacks.
Thanks for the links. Ill mess around a little more and let you guys know what I find.
than my Frankenstein javascript hacks.
LOL!
Best idea Ive found yet is to simply add an event listener in the Vue component ready() method:
ready() {
window.addEventListener('beforeunload', this.leaving);
},
methods: {
leaving: function () {
// Do stuff
}
}
Thanks to LinusBorg over at the Vue forums for this one. Seems like a pretty good solution to me. Everything is in the component, only a few lines of code...I should have thought of this hours ago.
Why not just store any typed in data for let's say 20 minutes or until the user submits it?
@davestewart @zachleigh Thats where I was going. LinusBorg has some very useful posts.
Yep, he's helped me loads :)
@davestewart @zachleigh Been playing around with this as a Vue learning exercise. First dug through Vue code and found how to register events programatically. Cannot get beforeunload to work. But I would share this.
ready: function () {
//window.beforeunload = this.leaving;
//window.onblur = this.leaving;
//window.onmouseout = this.leaving;
//document.getElementsByTagName('body')[0].addEventListener('beforeunload', this.leaving, false);
//debugger;
Vue.util.on(document.getElementsByTagName('body')[0], 'DOMFocusOut',
this.leaving,
false); // You can also just plug in the this.$el for getElementsByTag...
//window.onbeforeunload = function () {this.leaving()};
},
methods: {
leaving: function (event) {
//event.returnValue = "Write something clever here..";
//debugger;
fyi("Leaving..."); // Local Function Uses AlertJS library.
},
@jimmck Interesting. Didnt know you could do that sort of thing. Do you think there is an advantage to using the Vue event listener over the normal javascript event listener?
@zachleigh No I don't think so. I was looking at the beforeunload event and the documentation says it only applies to to the body element. I did not want to create a Vue instance on the Body tag and Vue does not seem to directly support that event. So I traced through the code and found the event setter method. Chrome debug gave me the memory mapping. Did you get beforeunload inside a Vue instance? At the end of day Vue is just Javascipt sitting on the DOM.But your question leads to interesting things. So much HTML/JS voodoo, the list of which events are supported by which browser, in which incarnation. It has always been a mystery to me.
This was nice...
http://help.dottoro.com/larrqqck.php
Never ran across these guys before.
@zachleigh Well this works. As the docs say, must done with window object and Vue (as it should now that I see) considers window a valid el You get the dialog. In chrome this works when event.returnValue is called. My fyi method is called, the return is ignored.
ready: function () {
//window.beforeunload = this.leaving;
//window.onblur = this.leaving;
//window.onmouseout = this.leaving;
//document.getElementsByTagName('body')[0].addEventListener('beforeunload', this.leaving, false);
//debugger;
// document.getElementsByTagName('body')[0]
Vue.util.on(window, 'beforeunload',
this.leaving,
false);
//window.onbeforeunload = function () {this.leaving()};
},
methods: {
leaving: function (event) {
event.returnValue = "event seems to need to be set";
//debugger;
fyi("Leaving...");
//return event;
},
@jimmck - beforeunload is on the window object. MDN is usually the best bet for most JS info:
Great labelling, code examples, and cross-browser info.
Taking into account other developers' worries about edge cases, I would probably just stick to something basic, like saving form values to a cookie. You could make the functionality modular by moving all this code to a mixin:
This example:
- saves form updates (see console) using a deep watch
- attempts to load any existing saved values when the page loads
- gets default values from the
getForm()method, which can be override on any mixin target
You didn't say this was specifically for a form, but this should work for any kind of stored model data :)
@davestewart Thats an interesting example. I might look into that if my current solution doesn't work out. Im currently firing off an ajax request to the server if the page ends without hitting a submit button. The ajax call saves the form data (only one field) in a backup column on the table. It works fine locally, but Im worried about lag time once the it goes up on the server. We'll find out tomorrow morning when I push it up.
Also, its a form with one field that can get very very long.
Because I was curious, here's another example, a little more extricated from Vue, but piggybacking its watch functionality:
Just the single call in ready to initialize everything, with a chained load() call if you need to:
VueCookieStore.create(this, 'path.to.object').load();
This could easily be updated to provide expires functionality, etc, etc.
Good luck with your deployment :)
@davestewart Thanks. unload is an event that fires from the body tag, you have to attach it to the window object if its not on the tag. I was just exploring Vue in response to @zachleigh question. The examples I found did not work in 1.26 and I have always had questions on the way Vue dispatched events.
Please or to participate in this conversation.