getElementsByClassName in ie8

18,539

Solution 1

Here is a quick solution by extending the Element.prototype and the document:

(function() {
if (!document.getElementsByClassName) {
    var indexOf = [].indexOf || function(prop) {
        for (var i = 0; i < this.length; i++) {
            if (this[i] === prop) return i;
        }
        return -1;
    };
    getElementsByClassName = function(className, context) {
        var elems = document.querySelectorAll ? context.querySelectorAll("." + className) : (function() {
            var all = context.getElementsByTagName("*"),
                elements = [],
                i = 0;
            for (; i < all.length; i++) {
                if (all[i].className && (" " + all[i].className + " ").indexOf(" " + className + " ") > -1 && indexOf.call(elements, all[i]) === -1) elements.push(all[i]);
            }
            return elements;
        })();
        return elems;
    };
    document.getElementsByClassName = function(className) {
        return getElementsByClassName(className, document);
    };

    if(Element) {
        Element.prototype.getElementsByClassName = function(className) {
            return getElementsByClassName(className, this);
        };
    }
}
})();

It's not always, however, the best idea to extend the prototype object, especially with a function named exactly like a non-existent native function. If you want to escape the problems caused by extension of the prototype, use this code:

(function() {
    var indexOf = [].indexOf || function(prop) {
        for (var i = 0; i < this.length; i++) {
            if (this[i] === prop) return i;
        }
        return -1;
    };
    window.getElementsByClassName = function(className,context) {
        if (context.getElementsByClassName) return context.getElementsByClassName(className);
        var elems = document.querySelectorAll ? context.querySelectorAll("." + className) : (function() {
            var all = context.getElementsByTagName("*"),
                elements = [],
                i = 0;
            for (; i < all.length; i++) {
                if (all[i].className && (" " + all[i].className + " ").indexOf(" " + className + " ") > -1 && indexOf.call(elements,all[i]) === -1) elements.push(all[i]);
            }
            return elements;
        })();
        return elems;
    };
})();​

That way, you can safely use a getElementsByClassName() function that accepts two arguments:

  1. className: the CSS class
  2. context: the node

Solution 2

IE8 doesn't support getElementsByClassName, but it does support querySelectorAll.

To use querySelectorAll, you need a valid class selector, which means it needs to use the Selectors API syntax for a class, which uses a . to signify a class.

function test2(className, link) {
    var e = document.querySelectorAll("." + className);

    for (var i = 0, len = e.length; i < len; i++) {
        e[i].style.display = "none";
    }

    link.innerHTML = "Expand";
}

Solution 3

You can implement it yourself if it's not there:

// shim for older browsers:
if (!document.getElementsByClassName) {
    document.getElementsByClassName = (function(){
        // Utility function to traverse the DOM:
        function traverse (node, callback) {
            callback(node);
            for (var i=0;i < node.childNodes.length; i++) {
                traverse(node.childNodes[i],callback);
            }
        }

        // Actual definition of getElementsByClassName
        return function (name) {
            var result = [];
            traverse(document.body,function(node){
                if (node.className == name) {
                    result.push(node);
                }
            });
            return result;
        }
    })()
}

Now you can use document.getElementsByClassName in older browsers. One difference between the shim and the native implementation is that the shim returns a real array rather than nodelist (or htmlelementcollection).

Share:
18,539
stefan
Author by

stefan

Updated on June 13, 2022

Comments

  • stefan
    stefan almost 2 years

    I'm trying to create a collapsable list in Internet Explorer 8 for the HTML I have:

    <li>
     <a href="#" onclick="test('node1')">hello</a>
     <ul id="node1" class="node" style="display:none">
       <li>Sub-item 1</li>
       <li>Sub-item 2</li>
     </ul>
    </li>
    <li>
     <a href="#" onclick="test('node2')">test</a>
      <ul id="node2" class="node" style="display:none">
       <li>Sub-item 1</li>
       <li>Sub-item 2</li>
     </ul>
    </li>
    

    in javascript i have

    function test2(className, link) {
     var e = document.getElementsByClassName(className);
    
     for (var i = 0, len = e.length; i < len; i++) {
       e[i].style.display = "none";
      }
    
      link.innerHTML = "Expand";
     }
    

    I'm using this to call it:

          <a href="#" onclick="test2('node', this)">Collapse</a>
    

    Unfortunately, this method is not working in IE8, and neither is querySelectAll. Can someone provide an example how to fix this please?

  • stefan
    stefan over 11 years
    im getting an error in ie saying does not support this property or method?
  • I Hate Lazy
    I Hate Lazy over 11 years
    Not sure why that would be. IE8 and higher supports it.
  • stefan
    stefan over 11 years
    is there another way to do this? it works on chrome and firefox but not ie8 for me
  • inhan
    inhan over 11 years
    Looks like it really does. Check it here: caniuse.com/queryselector
  • stefan
    stefan over 11 years
    yeah i dont understand this! so frustrating, how would you do it say if i were using ie7?
  • I Hate Lazy
    I Hate Lazy over 11 years
    @stefan: You would do a document.getElementsByTagName("*");, and the iterate the results and manually test for the class name. You'll be able to find other questions on StackOverflow that show how.
  • RobG
    RobG over 11 years
    @stefan—make sure IE is in standards mode by including a DOCTYPE. If there's no DOCTYPE, IE goes into quirks mode and some versions hide various W3C DOM methods.
  • Bruce
    Bruce over 10 years
    This is a great answer!
  • oxygen
    oxygen over 10 years
    Oh, why did you have to make me choose between the two? The decision is killing me!