Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

zachleigh's avatar

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?

0 likes
18 replies
zachleigh's avatar

@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.

jimmck's avatar

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

http://stackoverflow.com/questions/14645011/window-onbeforeunload-and-window-onunload-is-not-working-in-firefox-safari-o

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...

davestewart's avatar

@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.

zachleigh's avatar

@jimmck

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.

@jimmck @davestewart

Thanks for the links. Ill mess around a little more and let you guys know what I find.

1 like
zachleigh's avatar

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.

2 likes
EmilMoe's avatar

Why not just store any typed in data for let's say 20 minutes or until the user submits it?

jimmck's avatar

@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.
            },
zachleigh's avatar

@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?

jimmck's avatar

@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.

jimmck's avatar

@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;
            },
davestewart's avatar

@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 :)

zachleigh's avatar

@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.

davestewart's avatar

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 :)

jimmck's avatar

@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.