Internet Explorer Global Variable Blow ups
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:
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:
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.
The Voices of Reason
# re: Internet Explorer Global Variable Blow ups
# re: Internet Explorer Global Variable Blow ups
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();
# re: Internet Explorer Global Variable Blow ups
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
# re: Internet Explorer Global Variable Blow ups
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...
# re: Internet Explorer Global Variable Blow ups
# re: Internet Explorer Global Variable Blow ups
Other browsers unfortunately don't do that (hence a need for a lot of code.)
Is that connected?
# re: Internet Explorer Global Variable Blow ups
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.
# re: Internet Explorer Global Variable Blow ups
ie didnt have a problem with it though...I guess ie isnt the only one with issues.
# re: Internet Explorer Global Variable Blow ups
# re: Internet Explorer Global Variable Blow ups
@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.
# re: Internet Explorer Global Variable Blow ups
Do you have any idea of how to submit this bug to IE team? I couldn't find how to do that.
# re: Internet Explorer Global Variable Blow ups
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.
# re: Internet Explorer Global Variable Blow ups
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.
# re: Internet Explorer Global Variable Blow ups
Thanks a lot.
# re: Internet Explorer Global Variable Blow ups
Awesome as usual. I'm not sure where else I would find these nuggets.
# re: Internet Explorer Global Variable Blow ups
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.