Skip to content

Onbeforeunload throwing errors in IE – coding around it in ASP.NET

Some of the most popular questions on any web dev forum are:

  1. How do I trap the back button / stop people from clicking back?
  2. How do I stop someone from viewing source?
  3. How do I stop someone from closing a window/browser?

Short answer for all is: you can’t! Especially if you are supporting multiple browsers & multiple versions. There are tricks for the first two questions – and I notice Gmail is pretty clever to redraw the UI without a server trip when you click back. I’m pretty confident in saying – you can’t stop someone determined from viewing the source. Problem being that your webclient will need the source to display it!

How do you stop someone from closing a browser? Can you imagine how nasty pop-up ads would be if you couldn’t close them? There is an event in IE onbeforeunload. This will pop-up a dialog asking ‘Are you sure you want to navigate away from this page?’ plus your own text – if you attempt to navigate away from a page.

I usually try to talk people out of this – it is kind of bad usability. I must be losing my powers or getting complacent because I wound up using this on a project recently. This is how I discovered a problem where a user clicking ‘Cancel’ on the dialog will throw an error in IE. It only seems to happen if the navigation is initiated by client-side script. View a demo of it here.

A google for ‘onbeforeunload “unspecified error”‘ reveals a few articles about it. All centre around catching the ‘unspecified error’ in your javascript. Unfortunately my error was being thrown from within an AutoPostBack from a DropDownList – so I don’t have access to the script to catch the error. There’s a demo here, view the source here.

More scavenging around on Google and I find a way to hijack the postback. This is done by:

  • stashing ASP.NET’s postback function into a variable
  • replacing the postback function with your own
  • your function does what ever you have to do
  • then calls the ‘stashed’ postback function

var __oldDoPostBack = __doPostBack;
__doPostBack = CatchExplorerError;

function CatchExplorerError (eventTarget, eventArgument)
{
    try
    {
        return __oldDoPostBack (eventTarget, eventArgument);
    } catch (ex)
    {
        // don't want to mask a genuine error
        // lets just restrict this to our 'Unspecified' one
        if (ex.message.indexOf('Unspecified') == -1)
        {
            throw ex;
        }
        else
        {
            alert('caught the error!');
        }
    }
}

This will work nicely. Its important to note that firefox will enter into the catch – because it doesn’t like the onbeforeunload event. Also worth noting that the exception object also has a ‘description’ property in IE. I was originally testing this for the ‘unspecifed’ string – which throws another error in firefox. Both browsers seem happy if I use the ‘message’ property. The reference for the IE JScript Error object is here. The firefox reference doesn’t appear to be complete?

This still leaves one more problem: the select box is still has the new item selected. There’s not really any way to know that the user has clicked cancel on the ‘Are you sure?’ dialog. I could put something inside the catch in the CatchExplorerError. This would be a very very dodgy solution – as I’m relying on an error to occur to produce the UI that I want. What will happen when/if this bug gets fixed! A less dodgy solution (although I’m not entirely happy with it) would be to return the select box to its original selection in the onbeforeunload. This takes place before the dialog even appears. Yet at this point the browser has ‘decided on’ the form it will be sending to the server. So setting the selection here isn’t submitted up to the server.

The script ‘remembers’ the original selection of the select box by storing it in an expando property.

<select id="DropDownList1" onclick="this.oldIndex = this.selectedIndex">

Then I set the select box back to its stored value when onbeforeunload fires.

function body_onbeforeunload()
{

    var DropDownList1 = document.getElementById('DropDownList1');
    if (DropDownList1.oldIndex != undefined)
    {
        // return the selectbox to its oldIndex
        DropDownList1.selectedIndex = DropDownList1.oldIndex;
    }

    event.returnValue = "You sure?";
}

View a demo of the completed solution here, and the source here.

Post a Comment

Your email is never published nor shared. Required fields are marked *