Code with classList does not work in IE?

JavascriptInternet Explorer

Javascript Problem Overview


I'm using the following code, but having it fail in IE. The message is:

>Unable to get value of the property 'add': object is null or undefined"

I assume this is just an IE support issue. How would you make the following code work in IE?

Any ideas?

var img = new Image();
img.src = '/image/file.png';
img.title = 'this is a title';
img.classList.add("profilePic");
var div = document.createElement("div");
div.classList.add("picWindow");
div.appendChild(img);
content.appendChild(div);

Javascript Solutions


Solution 1 - Javascript

The classList property is not supported by IE9 and lower. IE10+ supports it though.
Use className += " .." instead. Note: Do not omit the space: class names should be added in a white-space separated list.

var img = new Image();
img.src = '/image/file.png';
img.title = 'this is a title';
img.className += " profilePic"; // Add profilePic class to the image

var div = document.createElement("div");
div.className += " picWindow";  // Add picWindow class to the div
div.appendChild(img);
content.appendChild(div);

Solution 2 - Javascript

As mentioned by othes, classList is not supported by IE9 and older. As well as Alex's alternative above, there are a couple of polyfills which aim to be a drop-in replacement, i.e. just include these in your page and IE should just work (famous last words!).

https://github.com/eligrey/classList.js/blob/master/classList.js

https://gist.github.com/devongovett/1381839

Solution 3 - Javascript

In IE 10 & 11, The classList property is defined on HTMLElement.prototype.

In order to get it to work on SVG-elements, the property should be defined on Element.prototype, like it has been on other browsers.

A very small fix would be copying the exact propertyDescriptor from HTMLElement.prototype to Element.prototype:

if (!Object.getOwnPropertyDescriptor(Element.prototype,'classList')){
    if (HTMLElement&&Object.getOwnPropertyDescriptor(HTMLElement.prototype,'classList')){
        Object.defineProperty(Element.prototype,'classList',Object.getOwnPropertyDescriptor(HTMLElement.prototype,'classList'));
    }
}
  • We need to copy the descriptor, since Element.prototype.classList = HTMLElement.prototype.classList will throw Invalid calling object
  • The first check prevents overwriting the property on browsers which support is natively.
  • The second check is prevents errors on IE versions prior to 9, where HTMLElement is not implemented yet, and on IE9 where classList is not implemented.

For IE 8 & 9, use the following code, I also included a (minified) polyfill for Array.prototype.indexOf, because IE 8 does not support it natively (polyfill source: Array.prototype.indexOf

//Polyfill Array.prototype.indexOf
Array.prototype.indexOf||(Array.prototype.indexOf=function (value,startIndex){'use strict';if (this==null)throw new TypeError('array.prototype.indexOf called on null or undefined');var o=Object(this),l=o.length>>>0;if(l===0)return -1;var n=startIndex|0,k=Math.max(n>=0?n:l-Math.abs(n),0)-1;function sameOrNaN(a,b){return a===b||(typeof a==='number'&&typeof b==='number'&&isNaN(a)&&isNaN(b))}while(++k<l)if(k in o&&sameOrNaN(o[k],value))return k;return -1});

// adds classList support (as Array) to Element.prototype for IE8-9
Object.defineProperty(Element.prototype,'classList',{
    get:function(){
        var element=this,domTokenList=(element.getAttribute('class')||'').replace(/^\s+|\s$/g,'').split(/\s+/g);
        if (domTokenList[0]==='') domTokenList.splice(0,1);
        function setClass(){
            if (domTokenList.length > 0) element.setAttribute('class', domTokenList.join(' ');
            else element.removeAttribute('class');
        }
        domTokenList.toggle=function(className,force){
            if (force!==undefined){
                if (force) domTokenList.add(className);
                else domTokenList.remove(className);
            }
            else {
                if (domTokenList.indexOf(className)!==-1) domTokenList.splice(domTokenList.indexOf(className),1);
                else domTokenList.push(className);
            }
            setClass();
        };
        domTokenList.add=function(){
            var args=[].slice.call(arguments)
            for (var i=0,l=args.length;i<l;i++){
                if (domTokenList.indexOf(args[i])===-1) domTokenList.push(args[i])
            };
            setClass();
        };
        domTokenList.remove=function(){
            var args=[].slice.call(arguments)
            for (var i=0,l=args.length;i<l;i++){
                if (domTokenList.indexOf(args[i])!==-1) domTokenList.splice(domTokenList.indexOf(args[i]),1);
            };
            setClass();
        };
        domTokenList.item=function(i){
            return domTokenList[i];
        };
        domTokenList.contains=function(className){
            return domTokenList.indexOf(className)!==-1;
        };
        domTokenList.replace=function(oldClass,newClass){
            if (domTokenList.indexOf(oldClass)!==-1) domTokenList.splice(domTokenList.indexOf(oldClass),1,newClass);
            setClass();
        };
        domTokenList.value = (element.getAttribute('class')||'');
        return domTokenList;
    }
});

Solution 4 - Javascript

    /**
 * Method that checks whether cls is present in element object.
 * @param  {Object} ele DOM element which needs to be checked
 * @param  {Object} cls Classname is tested
 * @return {Boolean} True if cls is present, false otherwise.
 */
function hasClass(ele, cls) {
    return ele.getAttribute('class').indexOf(cls) > -1;
}

/**
 * Method that adds a class to given element.
 * @param  {Object} ele DOM element where class needs to be added
 * @param  {Object} cls Classname which is to be added
 * @return {null} nothing is returned.
 */
function addClass(ele, cls) {
    if (ele.classList) {
        ele.classList.add(cls);
    } else if (!hasClass(ele, cls)) {
        ele.setAttribute('class', ele.getAttribute('class') + ' ' + cls);
    }
}

/**
 * Method that does a check to ensure that class is removed from element.
 * @param  {Object} ele DOM element where class needs to be removed
 * @param  {Object} cls Classname which is to be removed
 * @return {null} Null nothing is returned.
 */
function removeClass(ele, cls) {
    if (ele.classList) {
        ele.classList.remove(cls);
    } else if (hasClass(ele, cls)) {
        ele.setAttribute('class', ele.getAttribute('class').replace(cls, ' '));
    }
}

Solution 5 - Javascript

check this out

Object.defineProperty(Element.prototype, 'classList', {
	get: function() {
		var	self = this, bValue = self.className.split(" ")

		bValue.add = function (){
			var b;
			for(i in arguments){
				b = true;
				for (var j = 0; j<bValue.length;j++)
					if (bValue[j] == arguments[i]){
						b = false
						break
					}
				if(b)
					self.className += (self.className?" ":"")+arguments[i]
			}
		}
		bValue.remove = function(){
			self.className = ""
			for(i in arguments)
				for (var j = 0; j<bValue.length;j++)
					if(bValue[j] != arguments[i])
						self.className += (self.className?" " :"")+bValue[j]
		}
		bValue.toggle = function(x){
			var b;
			if(x){
				self.className = ""
				b = false;
				for (var j = 0; j<bValue.length;j++)
					if(bValue[j] != x){
						self.className += (self.className?" " :"")+bValue[j]
						b = false
					} else b = true
				if(!b)
					self.className += (self.className?" ":"")+x
			} else throw new TypeError("Failed to execute 'toggle': 1 argument required")
			return !b;
		}
		
		return bValue; 
	},
	enumerable: false
})

and classList will work!

document.getElementsByTagName("div")[0].classList
["aclass"]

document.getElementsByTagName("div")[0].classList.add("myclass")

document.getElementsByTagName("div")[0].className
"aclass myclass"

that's all!

Solution 6 - Javascript

In Explorer 11 classList.add works with single values only.

Element.classList.add("classOne", "classTwo");

In this case Explorer adds only first class and ignores the second one. So need to do:

Element.classList.add("classOne");
Element.classList.add("classTwo");

Solution 7 - Javascript

classList is not supported in IE < 9. Use [jQuery.addClass][1] or a polyfill like the one at https://developer.mozilla.org/en-US/docs/Web/API/Element/classList

[1]: http://api.jquery.com/addClass/ "jQuery.addClass"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWesleyView Question on Stackoverflow
Solution 1 - JavascriptRob WView Answer on Stackoverflow
Solution 2 - JavascripttagawaView Answer on Stackoverflow
Solution 3 - JavascriptKevin DrostView Answer on Stackoverflow
Solution 4 - JavascriptRitesh KumarView Answer on Stackoverflow
Solution 5 - JavascriptasdruView Answer on Stackoverflow
Solution 6 - JavascriptAlonadView Answer on Stackoverflow
Solution 7 - JavascriptJuan MendesView Answer on Stackoverflow