Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Internet Explorer Global Variable Blow ups


:P
On this page:

I ran into an odd behavior/bug with Internet Explorer today that I hadn’t noticed before in relation to global variable assignments. Check out the following code that fails for me in IE 8 both in compatibility and standards mode:

$(document).ready(function() {
    panelNewResource = $("#panelNewResource");
    panelRename = $("#panelRename");
    panelTranslate = $("#panelTranslate");
    panelRenameResourceSet = $("#panelRenameResourceSet");
    lstResourceIds = $("#lstResourceIds");

    if (lstResourceIds.get(0).options.length > 0)
        lstResourceIds.get(0).onchange();
});

This code blows up on each of the of the variable assignments. Can you spot why? Even without knowing what other code is in the page, this code should work. If the variable exists – it should be reassigned. If it doesn’t exist the variable should be declared – at global scope (window) – and allow assignment.

This code is supposed to set global jQuery references to several frequently used UI controls. This isn’t exactly a best practice as these variables aren’t declared explicitly, but this code works fine in every other browser and this is what effectively amounts single point startup code. Regardless I’m making the assumption that the variables will l be created at global scope on the window object (ie. window.panelNewResource).

The code breaks on the first line with an “Object doesn’t support this property or method”.

Trying to simplify the scenario and make sure it’s not jQuery that’s failing I assigned a new Object and ended up with the same result:

IE8bug

But here is where this gets really weird: The problem occurs only on variable names that match document ids. My page has an element with an ID of panelNewResource and this is blowing up. If I rename the variable to panelNewResourceId for example and run the same code it works just fine.

Opening up the watch window (in IE 8’s native debugger which is a nice enhancement) on panelNewResource shows what’s going on:

idReference

IE is actually creating a global object that matches the item’s ID!

A quick check into older version of IE seems to confirm that IE has always had this behavior – IE creates matching elements for all DOM elements on the page based on its id. I can’t believe I’ve never noticed this before – although I’m pretty sure I’ve probably run into this problem before :-} .

What’s even weirder though is why this assignment fails. Ok so there’s a reference to the DOM element, but since it’s a variable why can’t it be assigned and effectively overwrite the DOM reference? It turns out it’s because there’s some whacky scoping going on with these DOM elements – presumably it’s an accessor that can’t be assigned to.

This issue probably also accounts for the large number of script errors that pop up on various sites when browsing with IE with a script debugger enabled. This explains at least a few that I’ve investigated on my own or other sites where object not found errors seemingly would be valid but failed. This is an easy thing to miss especially if like me you have no idea about this funky behavior.

The fix for this is easy enough: Simply change the name of the variables so they don’t conflict with ID names, or - probably the better choice – properly predeclare your variables up front which is what I did for my code:

var localRes = null;
var panelNewResource;
var panelRename;
var panelTranslate;
var panelRenameResourceSet;
var lstResourceIds;

$(document).ready(function() {
    panelNewResource = $("#panelNewResource");
    panelRename = $("#panelRename");
    panelTranslate = $("#panelTranslate");
    panelRenameResourceSet = $("#panelRenameResourceSet");
    lstResourceIds = $("#lstResourceIds");

    if (lstResourceIds.get(0).options.length > 0)
        lstResourceIds.get(0).onchange();
});

Problem solved, but this just another lame ‘feature’ Microsoft included in IE. In theory the feature is not bad – having a global ref for any ID on the page is somewhat handy, except for the fact that there can be naming conflicts and of course the whole fact that it doesn’t work in any other browser.

I really wish IE would just go away. Die a quick death and start over Microsoft. Seriously. After all the talk this week at MIX how Microsoft cares about Web developer experience to see even ‘standards’ mode IE perpetuate proprietary inconsistencies like this are just lame.

Posted in JavaScript  

The Voices of Reason


 

Egil Hansen
March 22, 2009

# re: Internet Explorer Global Variable Blow ups

Hi Rick

I am by no means a javascript expert, so I will avoid trying to give a solution to your problem.

I do have a general suggestion that might help with your javascript pain as it did mine. After watching <a href="http://google-code-updates.blogspot.com/2009/03/doug-crockford-javascript-good-parts.html">Doug Crockfords presentation "Javascript: The Good Parts"</a> I was inspired to buy his book, and while I am only half way through it I can highly recommend it.

In particular he advocates to learn and stay away from the bad parts that are in javascript. Also, using his <a href="http://www.jslint.com/">JSLint</a> javascript verifier looks like a very good idea to keep thing working as expected.

ScobY9
March 22, 2009

# re: Internet Explorer Global Variable Blow ups

i ran into this problem some time ago. at the time, i wasn't really good at js so i just started learning by playing with debugger to see how to get a value i want and that's how i spotted this problem. anyways, my way to avoid this problem is to capitalize the first letter of dom element id or add the '_' before the element id

Chris Brandsma
March 22, 2009

# re: Internet Explorer Global Variable Blow ups

OK, aside from the fact that globals are evil in any language (JavaScript is not exempt), and implicit variable assignment is more evil (as true in VB6 as any other language).

Here is where I get WAY overly picky about a sample. If it is just sample code in order to illustrate an issue, forgive me. :)

Why pre-get all of the elements in the first place when you are getting them by ID? You aren't using those variables in that method. Seems like a waist for one of the fastest operations in the DOM (and JQuery).

Also, on this part of code:
lstResourceIds.get(0).onchange();

is that the same, or subtly different than:
lstResourceIds.change();

Stephen
March 22, 2009

# re: Internet Explorer Global Variable Blow ups

I took was wondering about using ".onchange()", never see that before

As for

"If I rename the variable to panelNewResourceId for example and run the same code it works just fine"

I've been into jQuery well over a year now, and time and time again i see the "standard" way (well, highly used by smart jQuery people anyways) to declare variables that are jQuery objects is to preface it with "$"

so:
panelNewResource = $("#panelNewResource");

to

$panelNewResource = $("#panelNewResource");

Not that I'm telling you how to code by any means, but just sharing what a lot of people out there use

Rick Strahl
March 22, 2009

# re: Internet Explorer Global Variable Blow ups

@Chris - The implicit assignment is on purpose for the article. But in this particular case I did do the implicit assignments some time ago (this is actually really old code that is now being refactored with jQuery) and appropriately it nipped me in the butt. Hence the discovery of this particular problem and this post - so this is a point made exactly for the purpose of this blog post - not as a best practice (and I mention that in the post). Implicit assignment is evil - totally agree on that, but the point here is that that code should work regardless of the semantics.

As to perf and the control assignments - you're probably right that this doesn't do much for perf, but in this case this is a rather complex form with about 50 plus operational functions that all use the same few list controls. I don't see a reason to get static ids or jquery selectors each time when you keep an easier to remember/write variable that will be slightly more efficient on top of it.

As to the get(0).onchange() - that's also a hold over from earlier code. The code I'm working on at the moment predates jQuery and I've been spending the last couple of days retrofitting it. I started with straight translations where appropriate and the get(0).onchange is one of those where I did a straight translation instead of doing the right jQuery adjustment. Retrofitting old code often is more time consuming than a re-write as I'm finding out on this single form UI <g>...

I know I'm making excuses <g> and I don't want to come off like I don't want to hear any critique of my code. By all means KEEP IT COMING - seriously, any conversation is valuable critical or otherwise and it helps me as well as others reading entries here. Thanks...

Rick Strahl
March 22, 2009

# re: Internet Explorer Global Variable Blow ups

@Stephen - I haven't seen that practice of $ prefix much. Personally I'm not a fan of it because as you read code it looks too much like an actual jQuery selector. I've teetered in this - I've often used a jVarName prefix for jQuery objects. OTOH, I've realized that it's so rare that I use DOM objects anymore that it's easier not prefix anything except the DOM objects <g>.

Mike Gale
March 22, 2009

# re: Internet Explorer Global Variable Blow ups

IE has a feature where you can avoid all that nonsense with getElementByID... and just use ID.whatever.

Other browsers unfortunately don't do that (hence a need for a lot of code.)

Is that connected?

Siderite
March 23, 2009

# re: Internet Explorer Global Variable Blow ups

Hah! I found myself in the same situation just yesterday. I know about IE creating objects with the names from element IDs so it was just a 5 minute dilemma for me. It used to be a major thing with old js scripts that were done for IE only.

What I don't get, though, is why can't the value be assigned? I mean, it seems that objects with those names are not created, but rather read only properties that point to DOM elements.

Tristan
March 23, 2009

# re: Internet Explorer Global Variable Blow ups

Heh, i ran into this the other day while I was removing HTC's from an intranet site. We had a var named screen, and despite having been previously defined as a global, firefox blew up on it until i renamed it varScreen.

ie didnt have a problem with it though...I guess ie isnt the only one with issues.

Andrew
March 23, 2009

# re: Internet Explorer Global Variable Blow ups


Vladimir Kelman
March 25, 2009

# re: Internet Explorer Global Variable Blow ups

@Rick, your wish was heard and IE will go away: http://research.microsoft.com/apps/pubs/default.aspx?id=79655.
@Rick and @Chris, Could you explain me please, what the implicit assignment is, how was it used above and why is it bad?
@Mike, I'm sure you're right: IE team decided to create global variables for all DOM elements to be able to use myID.whatever instead of getElementByID("myID").whatever ... a stupid decision.

Vladimir Kelman
March 25, 2009

# re: Internet Explorer Global Variable Blow ups

Here's a description of another IE bug and a workaround http://pro-thoughts.blogspot.com/2006/10/incorrect-behavior-of-windowonblur.html
Do you have any idea of how to submit this bug to IE team? I couldn't find how to do that.

BillE
April 06, 2009

# re: Internet Explorer Global Variable Blow ups

Your own comment about how much time it takes to re-write old code is exactly why this is still a part of IE. I'm sure this "feature" made coding easier for ie-only apps in the past. It will never die a quick death as long as that expense is around.

Standards do not solve the problem either. Until we can easily install multiple versions of a browser (ie, ff, safari, etc.) side by side and reference a specific version for our pages, we will always have problems.

Vladimir Kelman
October 19, 2010

# re: Internet Explorer Global Variable Blow ups

I got a nice message from Microsoft Connect Team saying that a bug was resolved in IE 9. They said, “This issue was resolved in Internet Explorer 9 Platform Preview Build 3 released on 6/23/2010… The fix prevents the error message. Note, IE still allows the DOM element to exist as a global javascript object."

Well, I’m not sure that keeping DOM elements in global JavaScript namespace is a good idea (other browsers don’t do it), but at least they found a workaround. It’s interesting to see how correctly it now supports HTML 5.

Mattias Svensson
May 09, 2011

# re: Internet Explorer Global Variable Blow ups

Thanks a lot rick! I had an hour of headache until I ran into your article, it never crossed my mind that having the same HTML-id on my script block as variable-name in the code would cause a problem (naturally, it didn't until I tried my code in IE... =)

Thanks a lot.

Greg Askew
May 01, 2012

# re: Internet Explorer Global Variable Blow ups

Hi Rick -

Awesome as usual. I'm not sure where else I would find these nuggets.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024