Change font of multiple elements using document.getElementsByClassName()? - javascript

How do you change font in CSS using document.getElementsByClassName()?
I tried using:
document.getElementsByClassName("classname").style.fontFamily="Your font";
but it doesn't work.
I am using Firefox 27.0.1 and it is supposed to be supported so I don't think that is a problem. Is there something wrong with my code?

First of all note that it's .getElementsByClassName() not .getElementsByClass().
.getElementsByClassName() method returns a NodeList of matching elements, Therefore, you have to loop through the returned list to apply the attribute, as follows:
var list = document.getElementsByClassName("classname");
for (var i = 0; i < list.length; ++i) {
list[i].style.fontFamily="Your font";
}

Use .getElementsByClassName() instead of .getElementsByClass().
Also, document.getElementsByClassName() returns an array of all child elements which have all of the given class names. Since it returns an array, you need to iterate through all the elements of the array like this:
elems = document.getElementsByClassName("classname")
for(elem in elems){
elem.style.fontFamily="Your font";
}

getElementsByClassName() returns an array-like collection of elements. Iterate over it like you would with a real array:
var elements = document.getElementsByClassName("classname");
for(var i = 0; i < elements.length; i++) {
elements[i].style.fontFamily="Times New Roman";
}
If you prefer something shorter, consider using jQuery:
$('.classname').css('fontFamily', 'Times New Roman');

Use this instead:
document.getElementsByClassName("classname").style.font="bold 20px Your Font";
If you are ok with using jQuery use:
$('.classname').css("font-family", 'Your Font');

Related

getElementsByClassName isn't returning all elements

I'm creating a button that I should highlight certain words within a specified class, but I am having issues with it returning all elements within the class. It will only work if I specify an index, so I'm assuming there may be something wrong with the existing "for loop". Any help is appreciated!
This will work, but only "highlights" the first element in the class, of course:
var bodyText = document.getElementsByClassName('test')[0].innerHTML;
for (var i = 0; i < searchArray.length; i++) {
bodyText = doHighlight(bodyText, searchArray[i], highlightStartTag,
highlightEndTag);}
document.getElementsByClassName('test')[0].innerHTML = bodyText;
return true;
This will not work at all:
var bodyText = document.getElementsByClassName('test').innerHTML;
for (var i = 0; i < searchArray.length; i++) {
bodyText = doHighlight(bodyText, searchArray[i], highlightStartTag,
highlightEndTag);}
document.getElementsByClassName('test').innerHTML = bodyText;
return true;
If you want to replace multiple words in multiple elements, you need two loops:
const testElements = document.getElementsByClassName('test');
for (const element of testElements) {
for (const search of searchArray) {
element.innerHTML = doHighlight(element.innerHTML, search, highlightStartTag, highlightEndTag);
}
}
As you can see getElementsByClassName is pluralized (Elements). Indeed a same class can be assigned to multiple HTML elements. You won't find any way to ommit the [0] and you shouldn't anyway as it might mean you're getting data from the wrong node. If you need data from a specific element that you can ensure is unique then you need to give it an id and use getElementById instead.
You cannot access innerHTML in something which returns an htmlcollection
document.getElementsByClassName('test').innerHTML
Because it's written in plain english: getElementsByClassName. plural.
"Elements".
with an "s" at the end...
meaning it's a (sort of) Array (an htmlcollection)

For loop only iterates once when trying to remove classes from elements

In Javascript I have a function that should find the elements on the page that have the "connected" class, and when a button is clicked the classes for these elements are cleared. I have written this code:
var prev_connected = document.getElementsByClassName("connected");
if (prev_connected.length > 0) {
for (var j = 0; j < prev_connected.length; j++) {
prev_connected[j].removeAttribute("class");
}
}
However, it only ever deletes the class attribute of the first "connected" element on the page. When I have two "connected" elements, I have confirmed that the "prev_connected" array does hold 2 values, but for some reason the for loop never reaches the 2nd one. Is there something I'm doing wrong? Thanks.
The result of getElementsByClassName is live, meaning that as you remove the class attribute it will also remove that element from the result. Using querySelectorAll is more widely supported and returns a static NodeList.
Also, you can more easily iterate the list using a for...in loop.
I would not recommend making an extra copy of the live list just to make it static, you should use a method that returns a static NodeList instead.
var prev_connected = document.querySelectorAll(".connected");
document.getElementById('demo').onclick = function() {
for(var i in Object.keys(prev_connected)) {
prev_connected[i].removeAttribute("class");
}
}
.connected {
background: rgb(150,200,250);
}
<div class="connected">Hello</div>
<div class="connected">Hello</div>
<div class="connected">Hello</div>
<div class="connected">Hello</div>
<div class="connected">Hello</div>
<button id="demo">Remove the classes!</button>
This is due to prev_connected being a live nodelist. When you update the element with that class it removes it from the nodelist which means the length of the nodelist reduces by one which means j is trying to find element 2 in an nodelist of length 1 which is why it doesn't work after the first iteration.
You can see this happening in the console in this demo.
One way you can fix this is by converting the nodelist to an array:
var prev_connected = [].slice.call(document.getElementsByClassName("connected"));
You should iterate in the opposite direction and use elem[i].classList.remove('name') for removing class name from each element Demo
document.getElementById("button").onclick = function () {
var prev_connected = document.getElementsByClassName("connected");
console.log(prev_connected);
for (var i = prev_connected.length - 1; i >= 0; i--) {
prev_connected[i].classList.remove("connected");
console.log(i, prev_connected[i - 1]);
}
}
There are another answers: https://stackoverflow.com/a/14409442/4365315

jQuery hasClass 'is not a function'

I want to check with jQuery which li element from a list of li elements is the active one (they represent a menu, and I want to check which menu item is currently active).
So, I store all the li items in a variable, myElements. Then I ask the length of myElements, and apply some style changes to them, up to here everything works. Apparently this way my variable myElements is a Nodelist, not an array, so I declare another variable; myElements_array, which contains the same elements as myElements and is an array (also tested and it works).
Then I try to check which of the elements from myElements_array has the 'current-menu-item' class, but it doesn't work and the google chrome console says there's an error: 'Uncaught TypeError: myElements_array[j].hasClass is not a function'. Does anyone have an idea what the reason might be?
<script type='text/javascript'>
var myElements = jQuery("#navbar > ul > li");
var count = myElements.length;
for (var i = 0; i < myElements.length; i++) {
myElements[i].style.width = (100/count)+'%';
}
var myElements_array = [];
for(var i = myElements.length; i--; myElements_array.unshift(myElements[i]));
var j = 0;
while (! myElements_array[j].hasClass('current-menu-parent') ) {
j++;
}
document.write(j);
</script>
Problem is the index you are pulling from the array is a DOM node when you use bracket notation and it is not a jQuery object. DOM does not have hasClass.
You can either store the jQuery version or change it to jQuery
while (! $(myElements_array[j]).hasClass('current-menu-parent') ) {
or use classList contains
while (! myElements_array[j].classList.contains('current-menu-parent') ) {
or use eq() instead of referencing the DOM
while (! myElements_array.eq(j).hasClass('current-menu-parent') ) {
When you access a jQuery object as if it's an array, it returns the raw DOM element object, not a jQuery object. If you want a jQuery object, use .eq() rather than an array index:
while (myElements.eq(j).hasClass('current-menu-parent') ) {
j++;
}
You could also use:
j = myElements.index(myElements.find(".current-menu-parent:first"));
You shouldn't loop through elements inside an jQuery object like that. You're tyring to use jQuery methods on normal dom objects. Use this instead:
$("#navbar > ul > li").each(function(){
$(this).hasClass("current-menu-parent");
});

getElementsByClassName vs querySelectorAll

if I use
var temp = document.querySelectorAll(".class");
for (var i=0, max=temp.length; i<max; i++) {
temp[i].className = "new_class";
}
everything works fine. All nodes change their classes.
But, with gEBCN:
var temp = document.getElementsByClassName("class");
for (var i=0, max=temp.length; i<max; i++) {
temp[i].className = "new_class";
}
I get error. Code jumps out of the loop at some point, not finishing the job with msg "can't set className of null".
I understand that this is static vs live nodelist problem (I think), but since gEBCN is much faster and I need to traverse through huge list of nodes (tree), I would really like to use getElementsByClassName.
Is there anything I can do to stick with gEBCN and not being forced to use querySelectorAll?
That's because HTMLCollection returned by getElementsByClassName is live.
That means that if you add "class" to some element's classList, it will magically appear in temp.
The oposite is also true: if you remove the "class" class of an element inside temp, it will no longer be there.
Therefore, changing the classes reindexes the collection and changes its length. So the problem is that you iterate it catching its length beforehand, and without taking into account the changes of the indices.
To avoid this problem, you can:
Use a non live collection. For example,
var temp = document.querySelectorAll(".class");
Convert the live HTMLCollection to an array. For example, with one of these
temp = [].slice.call(temp);
temp = Array.from(temp); // EcmaScript 6
Iterate backwards. For example, see #Quentin's answer.
Take into account the changes of the indices. For example,
for (var i=0; i<temp.length; ++i) {
temp[i].className = "new_class";
--i; // Subtract 1 each time you remove an element from the collection
}
while(temp.length) {
temp[0].className = "new_class";
}
Loop over the list backwards, then elements will vanish from the end (where you aren't looking any more).
for (var i = temp.length - 1; i >= 0; i--) {
temp[i].className = "new_class";
}
Note, however, that IE 8 supports querySelectorAll but not getElementsByClassName, so you might want to prefer querySelectorAll for better browser support.
Alternatively, don't remove the existing class:
for (var i=0, max=temp.length; i<max; i++) {
temp[i].className += " new_class";
}

Select and add class in javascript

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.
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
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
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 ;)
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
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.
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');
}

Categories

Resources