How to prevent browser message "Leaving site? Changes you made may not be saved."?

I was thinking this (and wrote ‘probably not’) :wink:

28%20PM

so what you need is: A handled error occurs :slight_smile:

edit: You probably though about it…

  • show ‘one moment please’… refresh your page, then detect it before doing anything else, and then redirect to the specific page… insane? :sweat_smile: (only as backup solution…)

Yep. Also, as for my CSS idea, it seems to be a non-starter as well. That modal dialog is like a total super-mega modal that blocks all interaction with the browser. So I can’t even click the console’s element inspector to see what class or id the modal has…

Also, I’ve tried detecting this as “Unhandled Error Occurs” but that does not trap it either. This is one of those cases where Bubble is trying to be helpful, but it’s simply not! :stuck_out_tongue:

Yes, that would be insane. (And it won’t work - Bubble will always intercept as far as I can tell.)

Just wanted to add I’m experiencing this issue as well with a plugin I’m creating.
I agree @Keith that this isn’t a plugin issue but a bubble feature which is undesirable in many cases.

In my situation I’ve created a new Fullcalendar plugin (releasing soon) which allows adding several Google Calendars.
When a google Calander event is clicked from fullcalendar, by default this opens Google Calender in a new window (tab) showing details of that event.
But in bubble I get this browser message alert whenever this happens, i.e. when I click on a google event from my bubble fullcalendar.

2 Likes

Yep! That’s exactly how this dialog is triggered and there just needs to be a way to suppress it when that behavior is undesirable.

Many potential workarounds discussed (to the point of hilarity) in my other thread on this. There’s no obvious or even obtuse workaround that can be fashioned, AFAICT:

Thanks for the feedback on this thread and the other @keith one. To give you more context on this message, it displays when there is a page change action when some workflows have not completed. If you have an example where all workflows are completed and then you are still getting this message, please submit a bug report with the reproducible steps. It may not be wise to disable this message entirely but we can look into top use cases to support.

2 Likes

Thanks @neerja for the explanation.

It makes sense and I understand the behavior now.
Your explanation is very helpful as I know how to avoid this now.

This should be stated somewhere in the bubble reference manual if it’s not already there (couldn’t find it).
Thanks again

Thanks, @neerja. I totally believe you when you say that this dialog is only supposed to appear when there is a pending workflow action. However, I believe it can also be triggered simply by attempting to change the parent container’s URL. I think that is what’s triggering the dialog for me.

I believe I can build a very simple empty app that demonstrates this. Will do so…

And… well, @neerja, building a very simple app that triggers this behavior is actually not so simple. Based on your feedback, I’ve discovered a bit more:

In the context of my live page(s) that exhibit this behavior. It does seem that – if I put a long enough pause between all of the workflow steps that create/update data and the step that fires off the redirect action – the redirect will succeed without the “Leave Site?” nag dialog.

The weird thing is: I’ve tried to insert pauses all along the way to enforce a measure of synchronous behavior. Here’s the workflow where I’ve inserted short pauses between every single step (which theoretically forces Bubble to wait until each previous is complete, right?):

Here’s an example of what happens. In fact, there is a progress bar going… But how do I know when the progress bar is not displayed (and no actions are pending) so that we can safely and silently redirect? Image:

What I find is that – on my desktop system – if I set that final pause to be 2000 ms, this gives the progress bar time to complete and the redirect will in fact happen without a nag. However, this isn’t the right way to do things as the time required is dependent on a huge number of factors.

So, I guess the question is: How do I detect the same state that Bubble’s “Leave Site?” dialog is detecting? (That is, the state of no workflow actions being pending.)

@keith For most apps, this is straightforward but if you have an app where timing of multiple actions is critical and the completion of it is not intuitive, please share that test app so we have a reproduction case.

If process time is the challenge, you must do everything you can to create your workflows on schedule API. The progress bar has to be under 2 seconds, not 15 seconds or more.

It’s not stuck or anything. It completes in a second or two. It’s just we cannot know when the processes represented by that bar are complete. (But annoyingly, Bubble knows and so throws the Leave Site warning.)

Basically I need the equivalent of “await” for the previous workflow steps. Often, inserting pauses is a sufficient way to mimic that, but apparently not in this particular example.

I didn’t try that one, maybe it can help? I’m in patching mode! :slight_smile:
edit: just bought. Works great.

It’s the same app and page I noted in the bug report, @neerja. The only thing I can think here that might be messing up the synchronous nature of this workflow is the Schedule API Workflow step. (Question: Do those steps return a value? I’m away from my machine at the moment, but that’s my next thing to look at.)

According to the plugin, it sounds to have a returned value.

events:

edit : just realized they have two products:
23%20PM

Actually (mostly for @neerja one more thing: There’s something that’s gotten completely lost in this discussion…

You will note that in my original post and my bug report, I talk about TWO workflow steps.

  1. The first is NAVIGATE to external page. That step ALWAYS succeeds silently and NEVER throws the “Leave Site?” dialog. (Using Navigate is useful, but Navigate can only change the URL displayed in the container, not the container’s parent. So, if my widget if hosted in an iFrame I need to also / instead of use a second technique - Run JavaScript - that allows me to access the parent window to do the redirect/replacement).

Why is it that Navigate always works and never causes the “Leave Site?” dialog to appear? This is just a wild-ass guess, but I assume that internally, Navigate is awaiting the completion of any promises that are outstanding in the page.

The fact that Navigate does not trigger the warning and that my alternative redirect options do is what lead me to surmise that the triggering had something to do with accessing parent.window.

The thing that does cause the “Leave Page?” dialog to be triggered is redirect technique #2:

  1. If I need to redirect not just in the iFrame, but in the hosting container (that is, the browser of the user who is visiting one of my customers’ pages, upon which my widget is iFramed), I cannot use Navigate. Navigate does not enable opening a URL in a new tab (which is the same thing as “the container of my current reference container”).

So I must use Run JavaScript to execute that redirection. There are several ways to do this, but all behave the same way. Currently, I’m executing parent.window.location.replace("redirect_url"); but other similar functions all have the same behavior.

Run JavaScript does not have easy access to pending promises. So it would seem that, even if I put a pause in front of the Run JS action in my workflow, and in front of all other steps in my workflow, there are still some things are awaiting completion that I cannot easily await.

(I get that there’s a somewhat hacky solution: I’ve seen that the progress bar has a class [or perhaps id, I can’t recall] and I suppose one could run a function to make sure that element does not exist / wait until that element goes away before proceeding with the redirect.)

But that seems like a very un-bubble-like solution to the problem of delaying a workflow step until we are no longer awaiting completion of previous actions, right?

In fact, I can’t find a native Bubble way to make such a delay happen. Outside of inserting pause actions (which for whatever reason does not properly delay execution), the only thing left is to make workflow steps dependent on some prior step.

I’m pretty sure that the one that’s the hang up is “Schedule API Workflow”. While this is undocumented, it seems that Schedule API Workflow DOES return a value as the results of its step. The data type is text, but the text is always null AFAICT. Also, that null value seems to be returned immediately (that is, the return value is not just information free in itself, but also gives us no timing information).

So in the experiment of, “OK, well let’s ensure that all downstream actions are only executed when Schedule API Workflow has completed” is not something we can do. Because looking at “results of step x ‘Schedule API Workflow’” always just shows us a null value.

Here’s the example: Step 9 kicks schedules an API Workflow:

Step 10 takes its return value and puts it into a custom state:

Step 11 reports what we find to the console:

The console reports that our custom state is null. In fact, this value is printed to the console almost immediately. And, even though all of our preceding steps MUST have executed (all of them are involved in assembling the data that we are now sending to the API Workflow), we now know that it is, in fact step 9 that’s the fly in the ointment here.

Step 9 gives us a return value of null immediately and, so, all downstream workflow steps are free to continue. These steps are very lightweight and seem to complete a short time before step 9 is actually done, causing us to reach step 17 nearly instantaneously:

Here’s the page at that moment:

As you can see, we’ve already gotten to the point where the JavaScript redirect is triggered (by a Custom Event that I’ve not shown above). The blue progress bar (though it will not take long to complete) must represent our friend Step 9.

Now, in the demonstration above, we’re triggering the JavaScript redirect. Here’s the OTHER version. Let’s say that I now change my preferences such that we will execute the Navigate redirect instead (and, in fact, I’ve just done that in my backend). Here’s what happens in that case:

In this case, the JS redirect will not fire, but the Navigate redirect will. Here are those workflow steps in the separate Custom Event workflow triggered by the boolean state (step 17) of the workflow we examined above:

What I observe in that case is that, in fact, there’s a slight delay before the redirect happens. It’s clear that “Open an external website” is aware of pending processes and only proceeds once those things are complete.

So, a couple of potential Bubble enhancements that would solve my issue (and possibly the issues of others who have run into this behavior):

  1. Give “Open an external website” an option for “open in parent’s window” (this would be helpful – and not problematic in terms of popup blocking – when the current container is an iFrame).

  2. Give us a version of pause that is process-aware. Basically, a workflow action that does whatever it is that the internal code of “open in parent’s window” is doing prior to actually executing the redirect action.

After having given this a really close look, I do agree that it’s unwise to be able to override “Leave Site?” but on the flip-side, we need some sort of Bubble-native way to do that same evaluation and only trigger fancy redirection actions once safe to do so (if we desire to do them silently, which we do!).

Best Regards,
Keith

1 Like

@keith do you get the same issue if the page redirects itself to a url? if not (most likely from what I’ve used) how about the iframe send a message to the parent window, then the parent window redirects itself.

I don’t have control over code in the site hosting the iFrame. That’s someone else’s site. It’s totally sufficient that I can cause that parent to redirect.

That’s not the root problem. The root problem here is what seems to be a bug in Schedule API Workflow (SAPIW) – while in the workflow editor you can see that it is supposed to report a return value, this action does not (it seems to notify the workflow that it is COMPLETE, when in fact it has only started) and that keeps my workflow from being able to know when all pending workflow actions are complete, and that causes my redirect JavaScript to execute while actions are still pending… leading to the “Leave Site?” dialog.

What’s going on here (which I’m documenting below in great detail for a new bug report about SAPIW) might also explain many similar issues that arise in terms of ensuring synchronous behavior of Bubble workflows when that is required.

We are missing an essential state or two in terms of mimicking the behavior of native Bubble elements. We don’t have a general, programmatic way to know if there are pending workflow actions, for example, except by the tools we are already familiar with (using pause, evaluating the state of return values from workflow steps, etc.

Conversely, not all Bubble actions are well-behaved vis-a-vis our current capabilities to interact with and control them in a workflow.

Schedule API Workflow is one of these. Clearly, it is intended that Schedule API Workflow should report a return value (probably the ID of the scheduled workflow, but since it’s undocumented we can’t know) to signal that it has competed the scheduling (and delay workflow execution if that’s important). But it does not do that. It immediately reports a null value.

Whatever is happening behind the scenes, the net effect is that SAPIW (Step 9) has effectively signaled that its return value is ready for inspection. So Step 10 evaluates that value and puts it into the custom state. We see via Step 11 that the value is null.

There are two things wrong here. First, that Step 10 has executed is supposed to imply that Step 9 (SAPIW) has returned (as Step 10 cannot evaluate the return value until it’s available for inspection). This is clearly not the case, however, as the progress bar is still going. Step 9 has signaled completion prematurely (I think what it actually does is signals that it’s started!).

Second, the value “returned” is null. This shouldn’t surprise us as we know that Step 9 has not in fact competed. So, whatever this return value is supposed to represent, we can’t expect it to make any sense at this point.

(The question remains: What is the return value of SAPIW supposed to represent? The fact that the return value is of type text implies that it’s intended for a unique ID. But again, this is not documented — so I’m just making an assumption here.)

It’s only when we hit these edge cases that we start to see certain capabilities we didn’t know about.

Of course it makes perfect sense that “Open external website” would internally ensure that the redirect would not prematurely leave the page and interrupt pending workflow actions.

Ok, cool. So, my enhanced, custom version of “open external website” (which is just a JavaScript redirect that operates on the app’s parent’s window rather than the app’s window) just needs to wait until pending workflow actions are complete.

Alright, easy-peasey. We’ll just… oh… ummm … hmmm… hey, there’s no way for me to do that.

We know that when we fire a workflow action something will happen and that it will take some amount of time to happen. We also know that — even though we do not receive an event or an explicit notification that an action has competed — we can understand IMPLICITLY that an action has competed by examining its return value.

We understand that, if we request that a downstream action (workflow step) examine the return value of a previous step, we can be assured that that downstream step cannot and will not execute until such time as that return value is actually available for evaluation.

But as we can see, some return values (at least the one from Schedule API Workflow) cannot be trusted. So the presence of that workflow step breaks this workflow in that we no longer know and can no longer control when it will compete.

In fact, both Run JavaScript and Open External Website in my example are called “too early”. However, Open External Website has some internal code that awaits all pending workflow actions before doing the redirect. (So if Open External Website is triggered, the page redirects silently.) If Run JavaScript is triggered, it executes its redirect immediately, causing the “Leave Site?” dialog to appear as the Schedule API Workflow step is not yet complete.

So, in summary, @neerja in support is correct: The “Leave Site?” dialog really does only appear when there are pending workflow actions that might be disrupted if we leave the page. (So for anyone else wondering about this dialog – that’s what’s going on.) I’m asking them to close my submitted bug about “Leave Site”.

However, I’ll be opening a new bug about Schedule API Workflow’s inaccurate reporting of return value.

As far as working around this problem with Run JavaScript: There’s no easy way to tell if there are pending workflow actions in some queue. We do have a second-order hint about this in the Progress Bar. So I suppose one could await executing the redirect function until one finds the Progress Bar is not present on the page.

(As I mentioned previously, the Progress Bar does have a class or an id that one can key off of and I assume this is how Zeroqode’s progress bar plugin works. I don’t think this is the most robust solution as I’m not sure how much I trust the progress bar given that we see some bugs in how workflow actions – at least in the case of SAPIW – can have bugs in terms of reporting their completion, but at the moment this seems like all we have to go on.

A more robust solution would be to have a native Bubble action or state that can report to us the status of the pending workflow queue. This would be a very helpful thing in many applications/use cases!)

One additional thought I’d like to add - we’ve found it very hard to debug this issue in our app because by turning on debug_mode, it slows the app down and runs everything in order, and that inherently seems to prevent this browser message from being triggered. And, without debug mode, it’s hard to know what’s really going on.

As such, it’d be nice if the fact this message was triggered was captured in the logs, and perhaps the description could explain which action was still running that caused it to be triggered.

Just a thought.

1 Like

Thanks @keith for the walkthrough of your tests. We will keep a lookout for the returned values bug report. The feature request for reporting real-time status for workflows sounds similar to something we are working on so more to come.

1 Like

The documentation states that it returns the ID of the schedule, so it can be cancelled.

However, your scheduled date/time is set to current date/time, which means to run as soon as possible, which means the schedule is executed and so a schedule ID doesn’t make sense, i.e. a null return value is appropriate.

I do agree that this design misses out on the opportunity of waiting for a synchronous endpoint execution and returning something meaningful. For which we have the slightly awful workaround of calling the endpoint as if its external, through the API connector.

If turning on the ‘asynchronous’ setting isn’t enough, you can get the code to run further delayed from the workflow step by embedding it within a setTimeout callback.

EDIT - although this would be a guessing game as to whether the current or any other workflows are in progress.

1 Like