27

Cross Platform if possible, how can I select classes in Javascript (but not Jquery please -MooTools is fine though-) on code that I can't add an ID? Specifically, I want to add the class "cf" on any li below:

HTML

<div class="itemRelated">
  <ul>
<li class="even">
<li class="odd">
<li class="even">

I tried to fiddle it but something is missing:

Javascript

 var list, i;
list = document.getElementsByClassName("even, odd");
for (i = 0; i < list.length; ++i) {
    list[index].setAttribute('class', 'cf');
}

JSFiddle

ps. This question phenomenally has possible duplicates, (another one) but none of the answers makes it clear.

Community
  • 1
  • 1
Yannis Dran
  • 1,479
  • 2
  • 18
  • 24
  • Interested in compilance in particular IE version? – veritas Jan 23 '14 at 21:22
  • not exactly a particular IE version, just to support modern browsers and the *best possible* combination of old IE versions. I wouldn't mind if IE6 or IE7 are out of question for example, but if there's something usable, I would take it. – Yannis Dran Jan 24 '14 at 10:44

6 Answers6

43

Using plain javascript:

var list;
list = document.querySelectorAll("li.even, li.odd");
for (var i = 0; i < list.length; ++i) {
   list[i].classList.add('cf');
}

Demo

For older browsers you could use this:

var list = [];
var elements = document.getElementsByTagName('li');
for (var i = 0; i < elements.length; ++i) {
    if (elements[i].className == "even" || elements[i].className == "odd") {
        list.push(elements[i]);
    };
}
for (var i = 0; i < list.length; ++i) {
    if (list[i].className.split(' ').indexOf('cf') < 0) {
        list[i].className = list[i].className + ' cf';
    }
}

Demo


Using Mootools:

$$('.itemRelated li').addClass('cf');

Demo

or if you want to target specific by Class:

$$('li.even, li.odd').addClass('cf');

Demo

Community
  • 1
  • 1
Sergio
  • 28,539
  • 11
  • 85
  • 132
  • Thanks. Just to learn, what about if I want to add a second class just for li.odd? I tried this $$('li.even, li.odd").addClass('cf','sec'); but didn't seem to work. – Yannis Dran Jan 24 '14 at 12:09
  • @YannisDran, then you can separate them with a space. Check here: http://jsfiddle.net/n4L5w/2/ – Sergio Jan 24 '14 at 12:37
  • 1
    adding classes with `.addClass()` and space is not a great idea - works because the code does not check the arg passed but caused classList change to be rejected - see https://github.com/mootools/mootools-core/commit/bd6ac113600fa508017c29237cf03c36171e9603#commitcomment-4656198 - see how this can have an adverse effect here: http://jsfiddle.net/3EyzL/. `addClass` should not duplicate classes, adding space removes that safety. – Dimitar Christoff Jan 24 '14 at 12:53
  • @DimitarChristoff, thanks for the warning/correction ! Is `element.addClass('bar').addClass('foo');` the best solution then? – Sergio Jan 24 '14 at 12:55
  • 2
    as it stands in the current implementation, spaces will work fine - so as long as you are certain neither of the two classes are already on the element, use it. otherwise, chain two like you said. also see http://www.youtube.com/watch?v=hZJacl2VkKo - depends on the usecase and so on. – Dimitar Christoff Jan 24 '14 at 13:02
  • @YannisDran, please read good input from Dimitar in the comments here. – Sergio Jan 24 '14 at 13:03
  • 1
    Nice question Yannis! And great answer @Sergio ! Its very helpful. – Kunj Apr 15 '14 at 10:52
17

I know this is old, but is there any reason not to simply do this (besides potential browser support issues)?

document.querySelectorAll("li.even, li.odd").forEach((el) => {
    el.classList.add('cf');
});

Support: https://caniuse.com/#feat=es5

MuffinTheMan
  • 1,509
  • 20
  • 25
3

Using some newer browser objects and methods.

Pure JS: Details: old fashioned way, declaring stuff at the beginging than iterating in one big loop over elements with index 'i', no big science here. One thing is using classList object which is a smart way to add/remove/check classes inside arrays.

var elements = document.querySelectorAll('.even','.odd'),
    i, length;

for(i = 0, length = elements.length; i < length; i++) {
    elements[i].classList.add('cf');
}

Pure JS - 2: Details: document.querySelectorAll returns an array-like object which can be accessed via indexes but has no Array methods. Calling slice from Array.prototype returns an array of fetched elements instantly (probably the fastest NodeList -> Array conversion). Than you can use a .forEach method on newly created array object.

Array.prototype.slice.call(document.querySelectorAll('.even','.odd'))
 .forEach(function(element) {
    element.classList.add('cf');
});

Pure JS - 3: Details: this is quite similar to v2, [].map is roughly that same as Array.prototype.map except here you declare an empty array to call the map method. It's shorter but more (ok little more) memory consuming. .map method runs a function on every element from the array and returns a new array (adding return in inside function would cause filling the returned values, here it's unused).

[].map.call(document.querySelectorAll('.even','.odd'), function(element) {
    element.classList.add('cf');
});

Pick one and use ;)

veritas
  • 2,034
  • 1
  • 16
  • 30
2

querySelectorAll is supported in IE8, getElementsByClassName is not, which does not get two classes at the same time either. None of them work in iE7, but who cares.

Then it's just a matter of iterating and adding to the className property.

var list = document.querySelectorAll(".even, .odd");
for (var i = list.length; i--;) {
    list[i].className = list[i].className + ' cf';
}

FIDDLE

adeneo
  • 312,895
  • 29
  • 395
  • 388
2

As others mention for selecting the elements you should use .querySelectorAll() method. DOM also provides classList API which supports adding, removing and toggling classes:

var list, i;
list = document.querySelectorAll('.even, .foo');
for (i = 0; i < list.length; i++) {
    list[i].classList.add('cf');
}

As always IE9 and bellow don't support the API, if you want to support those browsers you can use a shim, MDN has one.

Ram
  • 143,282
  • 16
  • 168
  • 197
0

If you want to select elements with different classes all together then the best choice is querySelectorAll.

querySelectorAll uses CSS selectors to select elements. As we add the same CSS properties to different elements by separating them by a comma in the same way we can select those elements using this.

.even, .odd {
    font-weight: bold;
}

Both elements with class 'even' and 'odd' get bold.

let list = document.querySelectorAll('.even, .odd');

Now, both the elements are selected.

+Point: you should use classList.add() method to add class.

Here is the complete code for you.

let list = document.querySelectorAll('.even, .odd');

for (i = 0; i < list.length; ++i) {
    list.classList.add('cf');
}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Satish Chandra Gupta
  • 2,970
  • 1
  • 22
  • 22