Invalid procedure call or argument IE issue when iterating through document.styleSheets using $.each()
The problem
After thorough testing I found out that document.styleSheets
isn't a regular array in IE. That's why it breaks in $.each()
call when it reaches the end.
If we take a look at jQuery function itself it has a for
loop to iterate over an object that has a length
property, falsely believing it's an array. document.styleSheets
does have length
property, but it's obviously not an array. So when this for
loop in $.each()
is executed:
for (var value = object[0];
i < length && callback.call( value, i, value ) !== false;
value = object[++i]){}
it fails after the last element has been iterated over. As we may see this for
loop doesn't increment i
on its own but rather increments it while assigning a new value to value
.
We can check this manually as well. Write these two lines in any browser's address bar:
javascript:var a=[1,2,3];alert(a[3]);void(0);
javascript:alert(document.styleSheets[document.styleSheets.length]);void(0);
The first one runs fine in all browsers, but the second one fails in IE.
The solution
We have to rewrite the iteration over style sheets
var allRules;
$(function() {
var fileRules;
allRules = {};
// can't use $.each() over document.styleSheets because it's not an array in IE
for (var i = 0; i < document.styleSheets.length; i++)
{
fileRules = document.styleSheets[i].cssRules || document.styleSheets[i].rules;
$.each(fileRules, function() {
allRules[this.selectorText] = this;
});
}
});
Robert Koritnik
Remote web developer, consultant, enthusiast, geek.
Updated on August 27, 2022Comments
-
Robert Koritnik almost 2 years
I've written this code that iterates over all global style sheet rules and stores them in an array/object. I use this dictionary-like object later to change global rules rather than setting styles on individual elements.
Following code breaks in IE8 but works fine in Firefox3.7 and Chrome4.
var allRules; $(function() { var fileRules; allRules = []; $.each(document.styleSheets, function() { // get rules for any browser (IE uses rules array) fileRules = this.cssRules || this.rules; $.each(fileRules, function() { allRules[this.selectorText] = this; }); }); });
I get
Invalid procedure call or argument
error. When I try to debug it, this code sucessfully iterates through two CSS style sheet files with rules but when the second one's iteration is done, it fails.I can't seem to find an error in this code.