Alert user to unsaved changes before closing the page

I hope this isn’t cross posting, but SO hasn’t helped yet and it seems to me that alert before leaving changes on a page should be built into Rails or at least more straight forward. GitHub - codedance/jquery.AreYouSure: A light-weight jQuery "dirty forms" Plugin - it monitors html forms and alerts users to unsaved changes if they attempt to close the browser or navigate away from the page. (Are you sure?) hasn’t been updated in three years, so maybe a conflict with webpacker or a simpler solution? There must be since there is so little discussion about this issue.

Hi Greg,

The reason that this is so little discussion about this topic is that as a technique, registering a beforeunload handler hasn’t been a recommended practice for a long time:

  • it’s a blocking call, similar to confirm, alert and prompt, which means nothing else can run at the same time
  • Google is seriously considering dropping support for blocking calls and I suspect that would include beforeunload events
  • most apps these days make use of the browser History API to pushState new pages onto the stack without actually reloading the page, which makes the whole concept of beforeunload moot
  • while I’m certainly generalizing, users generally seem to have reasonable proficiency with their browsers in 2021, such that they don’t need to be told that leaving the page is leaving the page - making this more of a nuissance than help. Can you imagine if Amazon popped up blocking alerts to tell you that you have paid for your order, yet?

So, we’ve established that it’s kind of tacky, likely won’t even work this time next year, and single page apps don’t need to unload to move to a new page. What’s a Greg to do?

Suggestion 1: learn Stimulus and ditch jQuery. Yes, jQuery was awesome and important. These days, you’re cutting your potential way short. jQuery has its own event system which makes it fundamentally incompatible with everything current, and it’s only going to get worse. Stimulus will own your heart if you let it.

Suggestion 2: while I’m not fully convinced that saving form state is the best idea, one thing you could consider is using LocalStorage to hold on to your user’s input values. Just make sure that you clear it out after they submit, or the next time they come back to the form, they will see all of the values from last time and be justifiably confused.

leastbad. Thank you. I’m starting to look at Stimulus. And as a rank amateur, it will be difficult; but I’ll try. Particularly since it’s new and evolving. I’ll review the tutorials and blogs.

Seems like the leaving unsaved changes should be built into Rails.

I think I need a clue. What event am I watching for on window close?

While it’s a perfectly valid opinion, in that it’s fine to have them… given everything that I outlined, I admit that I’m curious as to why you think such a specific implementation detail - one that most folks aren’t interested in - should be a default feature in a general framework.

Again, you can create your own beforeunload event listener on window but it sounds like Google is removing blocking calls - so this behaviour will not work this time next year. The writing is on the wall, here: you need to approach this differently.

Tell me: why are you so convinced that you need to do this? 99%+ of the web does not do it. No major, popular sites do it.

1 Like

I’m probably not explaining it correctly. I’m only interested in windows with forms that have changes. And I suspected there is a good reason why it’s not a default, but some sites do you such a feature: image.

My use case is not main stream, but I’m developing a personal project and I’m adding data as I develop. And sometimes I end up down a rabbit hole of looking for a piece of information and accidentally hit Cmd-W for a window I’m seeing, but the active window is the Rails window I’m entering information into. I tend to use Chrome for the development and Safari to look for other information. So further chance for user error.

I guess I could just use KeyboardMaestro to intercept Cmd-W for Google. but then it would be for all windows, not just ones with uncommitted information. But I can try that easily.

Thank you for your comments.

Heh, well… I set myself up for you just needing to show one example. But can you find two!? (don’t - I’m kidding)

Alright, you’ve been warned that it’s not a recommended pattern and that it won’t work with Turbolinks/Turbo Drive and that even if you implement it today, there’s an excellent chance that the browsers will not support it soon and your code will stop working… if you still want to do it, this is when I show you how to do it.

Here’s the basic implementation, outside of any context:

window.addEventListener('beforeunload', function (e) {
  if (gregsFormIsDirty()) {
    e.preventDefault()
    e.returnValue = ''
  } else {
    delete e['returnValue']
  }
})

First, because the callback is defined with an anonymous function, the event listener can’t be removed - although, given the context, this might be the only time that’s okay since you’re about to refresh. Second the function has to have some way to know if your form is dirty. I looked at the jQuery plugin and my sense is that it’s outdated and over-engineered.

Second, I still think that your actual best bet is to explore other ideas such as using LocalStorage to hold your values. It’s probably the fastest way to implement what I think you want.

Final bit of advice: in my experience, when you’re obsessing over something niche like beforeunload hijacking instead of working towards building key functionality… it’s usually a sign that you’ve gone down a rabbit hole and are just fancy procrastinating from finishing up the important things in the project. Get everything working and then if at the end you still feel like it needs niche featues, take all of the time you need! Usually you end up realizing that keeping things super simple is best.

About amateurs learning Stimulus… I had barely written twenty lines of javascript (all of them jquery) up until a few years ago, and Stimulus fixed nearly all the issues I had with javascript. I actually find vanilla javascript syntax much easier to wrap my head around than jquery (which I find too terse and oneliner-y), but the event listeners and querySelectorAll and whatnot makes the structure hard to read. Stimulus really helps by taking care of simple stuff like click event listeners and target elements for you so you don’t fill your javascript up with var rubbishElement = document.querySelector(".rubbish") type lines, and instead use the target concept. This is one area where jquery was better than vanilla javascript, but Stimulus is better than both.

Take it from a fellow amateur - learn stimulus.

OK. OK. I’m trying Stimulus to do something like Using Hotwire with Rails for a SPA like experience | Dev thoughts by Mike Wilson.

A different rabbit hole.

Yeah, that looks a lot more complex than using Stimulus to use local storage for unsubmitted form content. But probably rewarding!