In order to find children objects of a certain class name, I had to create my own helper function
findChildrenByTagName = function(obj, name){
var ret = [];
for (var k in obj.children){
if (obj.children[k].className === name){
ret.push(obj.children[k]);
}
}
return ret;
}
An example of how it works is
var li = document.createElement('li');
var input = document.createElement('input');
input.setAttribute('class','answer_input');
li.appendChild(input);
console.log(findChildrenByTagName(li,"answer_input"));
However when I replace className above by class in the function above, the code doesn't work. So I am naturally wondering what the difference is between class and className. A quick search on google doesn't reveal anything.
Also what's the best way to return a list of children of a particular class name for a generic object? If such doesn't exist, is there a way to add a method to all objects so that I can call
li.findChildrenByTagName("answer_input");
instead of the global function above?
Let's break this into answerable parts:
Question 1:
What is the difference between class and classname in javascript?
Your title question.
Answer 1:
Class is an attribute in an html element <span class='classy'></span>
While, on the other hand, .className is a property that can by called on an element to get/set its class.
var element = document.createElement('span');
element.className = 'classy'
// element is <span class='classy'></span>
Setting the class can also be accomplished with .getAttribute('class') and .setAttribute('class', 'classy'). We change manipulate classes so often, however, that it merited its own .className method.
Question 2:
However when I replace className above by class in the function above, the code doesn't work. So I am naturally wondering what the difference is between class and className.
Answer 2: element.class is not a property.
Class may be an attribute of an element, but you can't call it like el.class. The way you do it is by el.className, like you already figured out. If you look at the MDN for Element, you'll see that elements have many properties and methods, but .class isn't one.
Question 3:
Also what's the best way to return a list of children of a particular class name for a generic object?
Answer 3: Use .getElementsByClassName
Rather than using a purpose-made function, people frequently "chain" methods one-after-another to achieve your desired effect.
Based on your needs, I think you're asking for the .getElementsByClassName method. Here are the full docs and an excerpt:
The Element.getElementsByClassName() method returns returns a live HTMLCollection [array] containing all child elements which have all of the given class names.
To reuse the example from your answer:
var li = document.createElement('li');
var input = document.createElement('input');
input.setAttribute('class','answer_input');
li.appendChild(input);
console.log(li.getElementsByClassName("answer_input")[0]);
// would return the <input class='answer_input'> as the first element of the HTML array
Don't get confused between the reserved word 'class' and 'className' attribute of DOM element.
According to MDN:
The name className is used for this property instead of class because of conflicts with the "class" keyword in many languages which are used to manipulate the DOM.
EDIT:
The 'class' word used on js 1.0 but in js 2.0 was merged with ECMAScript 4 which was rather unpopular and depreciated. but it is still a reserved word.
The general concept is that class is an object and className is "one" of its properties.Refer the links on how to use the class attribute for manipulation.Kindly correct me if my perception/understanding is wrong.
https://www.w3schools.com/jsref/prop_html_classname.asp
https://www.w3schools.com/jsref/prop_element_classlist.asp
Related
How do I get only one DOM element by class name? I am guessing that the syntax of getting elements by class name is getElementsByClassName, but I am not sure how many elements it's going to return.
document.getElementsByClassName('className') would always return multiple elements because conceptually Classes are meant to be applied to multiple elements. If you want only the first element in the DOM with that class, you can select the first element out of the array-like HTMLCollection returned.
var elements = document.getElementsByClassName('className');
var requiredElement = elements[0];
Else, if you really want to select only one element. Then you need to use 'id' as conceptually it is used as an identifier for unique elements in a Web Page.
// HTML
<div id="myElement"></div>
// JS
var requiredElement = document.getElementById('myElement');
Clarifications :
getElementsByClassName returns a Node List and not an array
You do not need jQuery
What you were looking for was probably document.querySelector :
How do I get only one DOM element by class name?
var firstElementWithClass = document.querySelector('.myclass');
Also see: https://developer.mozilla.org/en/docs/Web/API/Document/querySelector
You can use jQuery:
$('.className').eq(index)
Or you can use the javascript built-in method:
var elements = document.getElementsByClassName('className');
This returns a nodeList of elements that you can iterate and make what you want.
If you want only one, you can access the elements in the javascript version like this:
elements[index]
To anyone looking for a one liner
var first = document.getElementsByClassName('test')[0];
Use NodeList.item().
For example:
var first = getElementsByClassName('test').item(0);
You can try with this:
document.getElementsByClassName("className")[index]
This question already has answers here:
How to Get Element By Class in JavaScript?
(12 answers)
Closed 9 years ago.
Using JavaScript, we can get element by id using following syntax:
var x=document.getElementById("by_id");
I tried following to get element by class:
var y=document.getElementByClass("by_class");
But it resulted into error:
getElementByClass is not function
How can I get an element by its class?
The name of the DOM function is actually getElementsByClassName, not getElementByClassName, simply because more than one element on the page can have the same class, hence: Elements.
The return value of this will be a NodeList instance, or a superset of the NodeList (FF, for instance returns an instance of HTMLCollection). At any rate: the return value is an array-like object:
var y = document.getElementsByClassName('foo');
var aNode = y[0];
If, for some reason you need the return object as an array, you can do that easily, because of its magic length property:
var arrFromList = Array.prototype.slice.call(y);
//or as per AntonB's comment:
var arrFromList = [].slice.call(y);
As yckart suggested querySelector('.foo') and querySelectorAll('.foo') would be preferable, though, as they are, indeed, better supported (93.99% vs 87.24%), according to caniuse.com:
querySelector(all)
getElementsByClassName
Don't use w3schools to learn something
Refer to MDN for accurate information
Another option is to use querySelector('.foo') or querySelectorAll('.foo') which have broader browser support than getElementsByClassName.
http://caniuse.com/#feat=queryselector
http://caniuse.com/#feat=getelementsbyclassname
You need to use the document.getElementsByClassName('class_name');
and dont forget that the returned value is an array of elements so if you want the first one use:
document.getElementsByClassName('class_name')[0]
UPDATE
Now you can use:
document.querySelector(".class_name") to get the first element with the class_name CSS class (null will be returned if non of the elements on the page has this class name)
or document.querySelectorAll(".class_name") to get a NodeList of elements with the class_name css class (empty NodeList will be returned if non of. the elements on the the page has this class name).
you can use
getElementsByClassName
suppose you have some elements and applied a class name 'test', so, you can get elements like as following
var tests = document.getElementsByClassName('test');
its returns an instance NodeList, or its superset: HTMLCollection (FF).
Read more
I'm working on a JS class that creates several elements and attaches them to the DOM, and I would like for the class to also set the style attribute properties of those elements. I have a function already that does this for other attributes:
function setAttrs(el, attrValArray){
for(var i=0; i<attrValArray.length;i++){
el.setAttribute(attrValArray[i][0],attrValArray[i][1]);
}
}
The attrValArray input is a 2D array that would look something like
attrValArray = [["class","container"],["id","cc1]];
So what I want is to be able to create a similar array for style property pairs such as:
propValArray = [["display","inline-block"],["position","relative"]];
Which I would then pass to a similar setStyles function.
I could use the same setAttribute method, but instead of looping over the array and setting attributes individually I would have to construct a long string and pass the whole thing as the second argument of setAttribute since I am actually setting many properties of only 1 attribute. But I'd like to avoid this because of the fact that it would override any existing inline styles (not that I use inline styles, but for the sake of principle).
The better option is to set the properties of style on the element. I.e.
el.style.<property-to-set> = "property value";
This does not overwrite anything other than the specific property being set. But I don't see any way to select the "property-to-set" using values from a list. Is there an appropriate way around this?
To be clear, I already know that I can simply assign the desired style attributes to the to-be-created element classes/ids, and was actually wondering if that is the technically correct thing to do based on "good practices" and whatnot. That is what I plan on doing if there is no satisfying alternative.
Also, as stated in the question, I'm strictly interested in a pure JS solution, no JQuery or any other such library/framework.
I don't see any way to select the "property-to-set" using values from a list.
Unless I'm misunderstanding the question, you would do it pretty much the exact same way:
function setStyles(el, cssArray){
for(var i=0; i<cssArray.length;i++){
el.style[cssArray[i][0]] = cssArray[i][1];
}
}
Remember with objects, you can access properties using dot notation object.property or bracket notation object['property']. When you use bracket notation, the text inside the brackets is evaluated, just like when looking up indexes in an array (arrays are really just special objects with number properties).
Alternatively, you could build one long string out of all the property/values pairs and use setAttribute or cssText:
function setStyles(el, cssArray){
let cssText = '';
for(var i=0; i<attrValArray.length;i++){
cssText += cssArray[i][0] + ':' + cssArray[i][1] + ';';
}
el.style.cssText = cssText;
// or el.setAttribute('style', cssText);
}
I'm using Famo.us + Angular. I'm able to retrieve the classList of a Surface by doing this:
$scope.findElement = function() {
var elem = $famous.find("#colored-bg")[0].renderNode; // Returns Surface
console.log(elem.classList); // RETURNS: ["purple-bg", "container-border", "box-shadow"]
};
You can't perform any of the operations on Famo.us object which you normal could to any other object on the DOM. For example, I thought I could add, remove, or replace classes, similar to this:
document.getElementById('id').classList.add('class');
document.getElementById('id').classList.remove('class');
add and remove do not exist, though. I can return the class list, and even individual items from the list (ex: Just the first class), but you cannot alter it. Any suggestions?
The setClasses method takes an array and you can set classes using:
renderNode.setClasses(['white-bg', 'big-text']);
Use addClass by passing the class name to add a class using:
renderNode.addClass('big-text');
Use removeClass by passing the class name to remove a class using:
renderNode.removeClass('big-text');
Use toggleClass by passing the class name to add/remove based on whether it exists:
renderNode.toggleClass('big-text');
Figured it out, courtesy of Tony Alves in the Famo.us Slack Chat:
renderNode.setClasses(['white-bg']);
This information was found in the github docs. So the entire function looks like this:
$scope.findElement = function() {
var elem = $famous.find("#colored-bg")[0].renderNode;
console.log(elem);
elem.setClasses(['white-bg']);
console.log(elem.classList); // RETURNS: ["white-bg"]
};
setClasses will accept an array of strings, which it them places into the Fa-Surface.
It appears that sometimes object.setAttribute(attrib,value) isn't equivalent to object.attrib=value in javascript?
I've got the following code, which works fine:
var lastMonthBn = document.createElement('input');
lastMonthBn.value='<'; // This works fine
lastMonthBn.type='button'; // This works fine
But the following code doesn't:
var div = document.createElement('div');
div.class = 'datepickerdropdown'; // No luck here!
So i need to use the following:
div.setAttribute('class','datepickerdropdown');
My question is, why? From reading this, I thought that object.setAttribute(blah,value) was the same as object.blah=value??
Properties and Attributes aren't really the same, however the DOM exposes standard attributes through properties.
The problem you're facing specifically with the class attribute is that class is a future reserved word.
In some implementations the use of a future reserved word can cause a SyntaxError exception.
For that reason, the HTMLElement DOM interface provides a way to access the class attribute, through the className property:
var div = document.createElement('div');
div.className = 'datepickerdropdown';
Remember, attributes aren't the same as properties, for example:
Immagine a DOM element that looks like this:
<div></div>
If you add a custom attribute to it, e.g.:
myDiv.setAttribute('attr', 'test');
An attribute will be added to the element:
<div attr="test"></div>
Accessing attr as a property on the div element, will simply give you undefined (since is not a property).
myDiv.foo; // undefined
If you bind a property to an element, e.g.:
myDiv.prop = "test";
The getAttribute method will not be able to find it, (since is not an attribute):
myDiv.getAttribute('test'); // null
Note: IE wrongly messes up attributes and properties. :(
As I've said before, the DOM exposes standard attributes as properties, but there are some exceptions that you'll have to know:
The class attribute, is accessible through the className property (the problem you have).
The for attribute of LABEL elements, is accessible through the htmlFor property (collides with the for statement).
Attributes are case-insensitive, but the language bindings for JavaScript properties are not, so the convention is to use the names is camelCase to access attributes through properties, for example the ones formed by two words, e.g. cellSpacing, colSpan, rowSpan, tabIndex, maxLength, readOnly frameBorder, useMap.
It should be noted that browsers like Safari will NOT run JavaScript if keywords like "class" or "int" are present.
So it's a cross-browser support sort of thing. "class" is present in JS2.0 [I believe a package system is available there too]
...
I should also note that in IE, setAttribute [for non-class things, since setAttribute should be use-able for other members such as "style"] can be glitchy.