Uncategorized

Inconsistent Javascript behavior in Internet Explorer

My colleague Stefano had this case a few weeks ago, but since he has not a blog (yet smile_wink) and I’ve been partially involved in it, I thought this might be interesting to share…

So, here is the story: the customer wanted to disable a button inside the onBlur event of a textbox through client-side Javascript. Reason for this is client-side input data validation: if the user enters some unwanted text, the button must be disabled to prevent him to click it; if the value is then corrected, the button must be re-enabled. The problem is when the textbox has the focus and user presses the button; it will be disabled but it has two side effects:

  1. The button stays pressed
  2. The page is frozen and when user clicks wherever inside the IE window, it fires the onClick event of the button

The source code of the page looked like this:

<HTML>
    <HEAD>
        <script>
            function logWriteLine(sText)
            {
                log.innerHTML+=sText+"<BR/>";
            }
        </script>
    </HEAD>
    <BODY onload='text1.focus();'>
        <input type=text id=text1 onblur='logWriteLine("text1.onblur called");button1.disabled=true;'/>
        <BR/><BR/>
        <button id="button1" onclick='logWriteLine("button1.onclick called");'>button1</button>
        <BR/><BR/>
        <SPAN id="log"></SPAN>
    </BODY>
</HTML>

I tested this on all of my 3 machines in office and always worked just fine, while Stefano was able to reproduce the problem reported on his machines… Here is what he did:

  1. Open the page inside IE
  2. Type something inside the textbox (this is not essential thought, the problem will reproduce also with an empty textbox)
  3. Click the button (the onBlur event is fired); you’ll see “text1.onblur called” is written below the button
  4. At this stage the button on Stefano’s machine appeared “clicked” (even if grayed out), while on my machine it looked simply… disabled
  5. Click anywhere else in the page
  6. On Stefano’s machine every click fired a new onClick button event and “button1.onclick called” was appended to that sort of “trace” below the button; on my machine nothing happened

Seems that:

  • If the button gets disabled (by the onBlur) before it get pressed, the everything works:
    • Leaving the text box fires the OnBlur
    • The OnBlur disable the Button
    • Pressing the button has no effect since it is already disabled
    • The onClick of the button is never fired and everything keeps working
  • If the button gets pressed before and the disabled while it is pressed, then everything locks:
    • Leaving the text box fires the OnBlur
    • The button manage to be pressed before the OnBlur can disable it
    • The onClick of the button fires
    • The OnBlur manage to disable the button which remain pressed
    • Everything hangs

Note that the repro is not always consistent (depending on the machine), and it never repros with Firefox.

  • XP SP2 IE6: we could reproduce the problem
  • XP SP2 IE7: works fine
  • Vista, IE7: we could reproduce the problem
  • Another Vista, IE7: works fine
  • Win2003 IE7: works fine
  • another Win2003 IE7: works fine

Given an appropriate machine it systematically reproduce, but on that same machine this never happens with Firefox.

After some testing and log analysis on customer’s machine, It turned out that they were facing a kind of race condition. This explains that it is working on some machines but not on all even with the same binaries. Firefox is using a complete different script engine and complete different implementation of Event handling. In IE we do not have a special prioritization of the events; this means that disabling a button while an onClick event of the button is running or will be executed next, might end in a non predictable situation. If the input field has the focus and we click the button, two events are fired: in the onBlur event we disable the object which has the onClick event, which has also been fired. I’m not completely sure, but I don’t think there is an official rule how the browser should behave.

Now let’s consider the following page:

<html>
<head>
    <title>Untitled Page</title>
    <script type="text/javascript" language="javascript">
    
    ButtonHasFocus= false;
    
    function Init()
    {
        text1.focus();
    }
    
    function logWriteLine(sText)
    {
        log.innerHTML+=sText+"<br/>";
    }

    function TextOnBlur()
    {
        logWriteLine("text1.onblur called");

        if (!ButtonHasFocus)
            button1.disabled=true;         
    }
    
    function Button1OnClick()
    {
        logWriteLine("Button1OnClick called");
        // in case validation is not ok disable the button
        button1.disabled = true;
    }
        
    </script>    
</head>
<body onload="Init()">
    <input type="text" id="text1" onclick="ButtonHasFocus=false" onblur='TextOnBlur()'/>
    <br/><br/>
    <button id="button1" onmouseover="ButtonHasFocus=true" onmouseout="ButtonHasFocus=false" 
          onclick='Button1OnClick()'>button1</button>
    <br/><br/>
    <span id="log"></span>
</body>
</html>

Here we disable the button on its onClick event itself, while in the onBlur event we first check if the button is enabled or not, before disabling it. The only difference is that the onClick event gets fired anyway so you have to check here if the validation is ok before doing anything else. If it is not, disable the button. Here is what appears in our “trace” on the page:

text1.onblur called
Button1OnClick called

Notice the difference? Now both events are fired (and logged), while in customer’s sample only the onBlur event was fired and logged 😲. We reported this to the IE team, but I’m not sure if (and when) this behavior will be changed.

Hope you don’t find yourself in this tricky situation.

Cheers

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.