How to Get Element By Class in JavaScript? - javascript

I want to replace the contents within a html element so I'm using the following function for that:
function ReplaceContentInContainer(id,content) {
var container = document.getElementById(id);
container.innerHTML = content;
}
ReplaceContentInContainer('box','This is the replacement text');
<div id='box'></div>
The above works great but the problem is I have more than one html element on a page that I want to replace the contents of. So I can't use ids but classes instead. I have been told that javascript does not support any type of inbuilt get element by class function. So how can the above code be revised to make it work with classes instead of ids?
P.S. I don't want to use jQuery for this.

This code should work in all browsers.
function replaceContentInContainer(matchClass, content) {
var elems = document.getElementsByTagName('*'), i;
for (i in elems) {
if((' ' + elems[i].className + ' ').indexOf(' ' + matchClass + ' ')
> -1) {
elems[i].innerHTML = content;
}
}
}
The way it works is by looping through all of the elements in the document, and searching their class list for matchClass. If a match is found, the contents is replaced.
jsFiddle Example, using Vanilla JS (i.e. no framework)

Of course, all modern browsers now support the following simpler way:
var elements = document.getElementsByClassName('someClass');
but be warned it doesn't work with IE8 or before. See http://caniuse.com/getelementsbyclassname
Also, not all browsers will return a pure NodeList like they're supposed to.
You're probably still better off using your favorite cross-browser library.

document.querySelectorAll(".your_class_name_here");
That will work in "modern" browsers that implement that method (IE8+).
function ReplaceContentInContainer(selector, content) {
var nodeList = document.querySelectorAll(selector);
for (var i = 0, length = nodeList.length; i < length; i++) {
nodeList[i].innerHTML = content;
}
}
ReplaceContentInContainer(".theclass", "HELLO WORLD");
If you want to provide support for older browsers, you could load a stand-alone selector engine like Sizzle (4KB mini+gzip) or Peppy (10K mini) and fall back to it if the native querySelector method is not found.
Is it overkill to load a selector engine just so you can get elements with a certain class? Probably. However, the scripts aren't all that big and you will may find the selector engine useful in many other places in your script.

A Simple and an easy way
var cusid_ele = document.getElementsByClassName('custid');
for (var i = 0; i < cusid_ele.length; ++i) {
var item = cusid_ele[i];
item.innerHTML = 'this is value';
}

I'm surprised there are no answers using Regular Expressions. This is pretty much Andrew's answer, using RegExp.test instead of String.indexOf, since it seems to perform better for multiple operations, according to jsPerf tests.
It also seems to be supported on IE6.
function replaceContentInContainer(matchClass, content) {
var re = new RegExp("(?:^|\\s)" + matchClass + "(?!\\S)"),
elems = document.getElementsByTagName('*'), i;
for (i in elems) {
if (re.test(elems[i].className)) {
elems[i].innerHTML = content;
}
}
}
replaceContentInContainer("box", "This is the replacement text.");
If you look for the same class(es) frequently, you can further improve it by storing the (precompiled) regular expressions elsewhere, and passing them directly to the function, instead of a string.
function replaceContentInContainer(reClass, content) {
var elems = document.getElementsByTagName('*'), i;
for (i in elems) {
if (reClass.test(elems[i].className)) {
elems[i].innerHTML = content;
}
}
}
var reBox = /(?:^|\s)box(?!\S)/;
replaceContentInContainer(reBox, "This is the replacement text.");

This should work in pretty much any browser...
function getByClass (className, parent) {
parent || (parent=document);
var descendants=parent.getElementsByTagName('*'), i=-1, e, result=[];
while (e=descendants[++i]) {
((' '+(e['class']||e.className)+' ').indexOf(' '+className+' ') > -1) && result.push(e);
}
return result;
}
You should be able to use it like this:
function replaceInClass (className, content) {
var nodes = getByClass(className), i=-1, node;
while (node=nodes[++i]) node.innerHTML = content;
}

var elems = document.querySelectorAll('.one');
for (var i = 0; i < elems.length; i++) {
elems[i].innerHTML = 'content';
};

I assume this was not a valid option when this was originally asked, but you can now use document.getElementsByClassName('');. For example:
var elements = document.getElementsByClassName(names); // or:
var elements = rootElement.getElementsByClassName(names);
See the MDN documentation for more.

There are 3 different ways to get elements by class in javascript. But here for your query as you have multiple elements with the same class names you can use 2 methods:
getElementsByClassName Method - It returns all the elements with the specified class present in the document or within the parent element which called it.
function ReplaceContentInContainer(className, content) {
var containers = document.getElementsByClassName(className);
for (let i = 0; i < containers.length; i++) {
containers[i].innerHTML = content;
}
}
ReplaceContentInContainer('box', 'This is the replacement text');
<div class='box'></div>
querySelectorAll Method - It select element on the basic of CSS selectors. Pass your CSS class to it with a dot and it will return all the element having specified class as an array-like object.
function ReplaceContentInContainer(className, content) {
var containers = document.querySelectorAll(`.${className}`);
for (let i = 0; i < containers.length; i++) {
containers[i].innerHTML = content;
}
}
ReplaceContentInContainer('box', 'This is the replacement text');
<div class='box'></div>

I think something like:
function ReplaceContentInContainer(klass,content) {
var elems = document.getElementsByTagName('*');
for (i in elems){
if(elems[i].getAttribute('class') == klass || elems[i].getAttribute('className') == klass){
elems[i].innerHTML = content;
}
}
}
would work

jQuery handles this easy.
let element = $(.myclass);
element.html("Some string");
It changes all the .myclass elements to that text.

When some elements lack ID, I use jQuery like this:
$(document).ready(function()
{
$('.myclass').attr('id', 'myid');
});
This might be a strange solution, but maybe someone find it useful.

Related

How to write Javascript to search nodes - without getElementsByClassName

I'm very new at recursion, and have been tasked with writing getElementsByClassName in JavaScript without libraries or the DOM API.
There are two matching classes, one of which is in the body tag itself, the other is in a p tag.
The code I wrote isn't working, and there must be a better way to do this. Your insight would be greatly appreciated.
var elemByClass = function(className) {
var result = [];
var nodes = document.body; //<body> is a node w/className, it needs to check itself.
var childNodes = document.body.childNodes; //then there's a <p> w/className
var goFetchClass = function(nodes) {
for (var i = 0; i <= nodes; i++) { // check the parent
if (nodes.classList == className) {
result.push(i);
console.log(result);
}
for (var j = 0; j <= childNodes; j++) { // check the children
if (childNodes.classList == className) {
result.push(j);
console.log(result);
}
goFetchClass(nodes); // recursion for childNodes
}
goFetchClass(nodes); // recursion for nodes (body)
}
return result;
};
};
There are some errors, mostly logical, in your code, here's what it should have looked like
var elemByClass = function(className) {
var result = [];
var pattern = new RegExp("(^|\\s)" + className + "(\\s|$)");
(function goFetchClass(nodes) {
for (var i = 0; i < nodes.length; i++) {
if ( pattern.test(nodes[i].className) ) {
result.push(nodes[i]);
}
goFetchClass(nodes[i].children);
}
})([document.body]);
return result;
};
Note the use of a regex instead of classList, as it makes no sense to use classList which is IE10+ to polyfill getElementsByClassName
Firstly, you'd start with the body, and check it's className property.
Then you'd get the children, not the childNodes as the latter includes text-nodes and comments, which can't have classes.
To recursively call the function, you'd pass the children in, and do the same with them, check for a class, get the children of the children, and call the function again, until there are no more children.
Here are some reasons:
goFetchClass needs an initial call after you've defined it - for example, you need a return goFetchClass(nodes) statement at the end of elemByClass function
the line for (var i = 0; i <= nodes; i++) { will not enter the for loop - did you mean i <= nodes.length ?
nodes.classList will return an array of classNames, so a direct equality such as nodes.classList == className will not work. A contains method is better.
Lastly, you may want to reconsider having 2 for loops for the parent and children. Why not have 1 for loop and then call goFetchClass on the children? such as, goFetchClass(nodes[i])?
Hope this helps.

How to get html element's class tags

I'm using a custom modernizer config which has selected the features I employ in my page (and only those features).
So, I'd like to simply grab the className of the <html> of the page so I can check to see how many no- prefixed classes are present (maybe checking classlist.match(/no-/g).length) and determine if my javascript should just give up.
It's not clear whether I should use
document.getElementsByTagName('html').className
or
$('html').attr('class')
or
document.documentElement.className
I will go for:
document.documentElement.className;
Because doesn't involve any function's call, neither an additional layer like jquery. Ideally this one is the cleanest and the fastest.
you can use jQuery hasClass` method:
Determine whether any of the matched elements are assigned the given class.
if ( $('html').hasClass('no-something')) {
// do something here
}
If using plain JS, the equivalent would be:
document.getElementsByTagName('html')[0].className
If you are using jquery in your project why to not use this one:
var classList = $("html").attr('class').split(/\s+/);
var prefix = 'no-';
$.each( classList, function(index, item){
if (item.substring(0, 2) === prefix) {
//do something
}
});
?
var allClasses = [];
var allElements = document.querySelectorAll('*');
for (var i = 0; i < allElements.length; i++) {
if (allElements[i].hasAttribute("class")) {
var classes = allElements[i].className.toString().split(/\s+/);
for (var j = 0; j < classes.length; j++) {
var cls = classes[j];
if (cls && allClasses.indexOf(cls) === -1)
allClasses.push(cls);
}
}
}
console.log(allClasses);

How to get text from all descendents of an element, disregarding scripts?

My current project involves gathering text content from an element and all of its descendants, based on a provided selector.
For example, when supplied the selector #content and run against this HTML:
<div id="content">
<p>This is some text.</p>
<script type="text/javascript">
var test = true;
</script>
<p>This is some more text.</p>
</div>
my script would return (after a little whitespace cleanup):
This is some text. var test = true; This is some more text.
However, I need to disregard text nodes that occur within <script> elements.
This is an excerpt of my current code (technically, it matches based on one or more provided selectors):
// get text content of all matching elements
for (x = 0; x < selectors.length; x++) { // 'selectors' is an array of CSS selectors from which to gather text content
matches = Sizzle(selectors[x], document);
for (y = 0; y < matches.length; y++) {
match = matches[y];
if (match.innerText) { // IE
content += match.innerText + ' ';
} else if (match.textContent) { // other browsers
content += match.textContent + ' ';
}
}
}
It's a bit simplistic in that it just returns all text nodes within the element (and its descendants) that matches the provided selector. The solution I'm looking for would return all text nodes except for those that fall within <script> elements. It doesn't need to be especially high-performance, but I do need it to ultimately be cross-browser compatible.
I'm assuming that I'll need to somehow loop through all children of the element that matches the selector and accumulate all text nodes other than ones within <script> elements; it doesn't look like there's any way to identify JavaScript once it's already rolled into the string accumulated from all of the text nodes.
I can't use jQuery (for performance/bandwidth reasons), although you may have noticed that I do use its Sizzle selector engine, so jQuery's selector logic is available.
function getTextContentExceptScript(element) {
var text= [];
for (var i= 0, n= element.childNodes.length; i<n; i++) {
var child= element.childNodes[i];
if (child.nodeType===1 && child.tagName.toLowerCase()!=='script')
text.push(getTextContentExceptScript(child));
else if (child.nodeType===3)
text.push(child.data);
}
return text.join('');
}
Or, if you are allowed to change the DOM to remove the <script> elements (which wouldn't usually have noticeable side effects), quicker:
var scripts= element.getElementsByTagName('script');
while (scripts.length!==0)
scripts[0].parentNode.removeChild(scripts[0]);
return 'textContent' in element? element.textContent : element.innerText;
EDIT:
Well first let me say im not too familar with Sizzle on its lonesome, jsut within libraries that use it... That said..
if i had to do this i would do something like:
var selectors = new Array('#main-content', '#side-bar');
function findText(selectors) {
var rText = '';
sNodes = typeof selectors = 'array' ? $(selectors.join(',')) : $(selectors);
for(var i = 0; i < sNodes.length; i++) {
var nodes = $(':not(script)', sNodes[i]);
for(var j=0; j < nodes.length; j++) {
if(nodes[j].nodeType != 1 && node[j].childNodes.length) {
/* recursion - this would work in jQ not sure if
* Sizzle takes a node as a selector you may need
* to tweak.
*/
rText += findText(node[j]);
}
}
}
return rText;
}
I didnt test any of that but it should give you an idea. Hopefully someone else will pipe up with more direction :-)
Cant you just grab the parent node and check the nodeName in your loop... like:
if(match.parentNode.nodeName.toLowerCase() != 'script' && match.nodeName.toLowerCase() != 'script' ) {
match = matches[y];
if (match.innerText) { // IE
content += match.innerText + ' ';
} else if (match.textContent) { // other browsers
content += match.textContent + ' ';
}
}
ofcourse jquery supports the not() syntax in selectors so could you just do $(':not(script)')?

Javascript search for tag and get it's innerHTML

It's probably something really simple, but I'm just learning.
There's a page with 3 blockquote tags on it, and I'd need to get the innerHTML of the one containing a certain string. I don't know how to search/match a string and get the innerHTML of the tag containing the matched result.
Any help would be appreciated!
var searchString = 'The stuff in innerHTML';
var elements = document.getElementsByTagName('blockquote')
for (var i = 0; i < elements.length; i++) {
if (elements[i].innerHTML.indexOf(searchString) !== -1) {
alert('Match');
break;
}
}
:)
Btw there would be a much nicer method if you'd be using Prorotype JS (which is much better than jQuery btw):
var el = $$('blockquote').find(function(el) {
return el.innerHTML.indexOf('The string you are looking for.') !== -1;
});
You could of course also use regular expressions to find the string, which might be more useful (use el.match() for that).
If you need to search through every <blockquote> on the page, try this:
function findBlockquoteContainingHtml(matchString) {
var blockquoteElements = document.getElementsByTagName('BLOCKQUOTE');
var i;
for (i = 0; i < blockquoteElements.length; i++) {
if (blockquoteElements[i].innerHTML.indexOf(matchString) >= 0) {
return blockquoteElements[i].innerHTML;
}
}
return null;
}
Assign an id to the blockquote elements then you can get the innerHTML like this:
HTML:
<blockquote id="bq1">Foo</blockquote>
JS:
var quote1 = document.getElementById('bq1').innerHTML;
Be careful using innerHTML to search for text within a tag, as that may also search for text in attributes or tags as well.
You can find all blockquote elements using:
var elems = document.getElementsByTagName("blockquote")
You can then look through their innerHTML, but I would recommend instead looking through their textContent/innerText (sadly, this is not standardized across browser, it seems):
for (i in elems) {
var text = elems[i].textContent || elems[i].innerText;
if (text.match(/foo/)) {
alert(elems[i].innerHTML);
}
}

Get class list for element with jQuery

Is there a way in jQuery to loop through or assign to an array all of the classes that are assigned to an element?
ex.
<div class="Lorem ipsum dolor_spec sit amet">Hello World!</div>
I will be looking for a "special" class as in "dolor_spec" above. I know that I could use hasClass() but the actual class name may not necessarily be known at the time.
You can use document.getElementById('divId').className.split(/\s+/); to get you an array of class names.
Then you can iterate and find the one you want.
var classList = document.getElementById('divId').className.split(/\s+/);
for (var i = 0; i < classList.length; i++) {
if (classList[i] === 'someClass') {
//do something
}
}
jQuery does not really help you here...
var classList = $('#divId').attr('class').split(/\s+/);
$.each(classList, function(index, item) {
if (item === 'someClass') {
//do something
}
});
Why has no one simply listed.
$(element).attr("class").split(/\s+/);
EDIT: Split on /\s+/ instead of ' ' to fix #MarkAmery's objection. (Thanks #YashaOlatoto.)
On supporting browsers, you can use DOM elements' classList property.
$(element)[0].classList
It is an array-like object listing all of the classes the element has.
If you need to support old browser versions that don't support the classList property, the linked MDN page also includes a shim for it - although even the shim won't work on Internet Explorer versions below IE 8.
Here is a jQuery plugin which will return an array of all the classes the matched element(s) have
;!(function ($) {
$.fn.classes = function (callback) {
var classes = [];
$.each(this, function (i, v) {
var splitClassName = v.className.split(/\s+/);
for (var j = 0; j < splitClassName.length; j++) {
var className = splitClassName[j];
if (-1 === classes.indexOf(className)) {
classes.push(className);
}
}
});
if ('function' === typeof callback) {
for (var i in classes) {
callback(classes[i]);
}
}
return classes;
};
})(jQuery);
Use it like
$('div').classes();
In your case returns
["Lorem", "ipsum", "dolor_spec", "sit", "amet"]
You can also pass a function to the method to be called on each class
$('div').classes(
function(c) {
// do something with each class
}
);
Here is a jsFiddle I set up to demonstrate and test http://jsfiddle.net/GD8Qn/8/
Minified Javascript
;!function(e){e.fn.classes=function(t){var n=[];e.each(this,function(e,t){var r=t.className.split(/\s+/);for(var i in r){var s=r[i];if(-1===n.indexOf(s)){n.push(s)}}});if("function"===typeof t){for(var r in n){t(n[r])}}return n}}(jQuery);
You should try this one:
$("selector").prop("classList")
It returns a list of all current classes of the element.
var classList = $(element).attr('class').split(/\s+/);
$(classList).each(function(index){
//do something
});
$('div').attr('class').split(' ').each(function(cls){ console.log(cls);})
Update:
As #Ryan Leonard pointed out correctly, my answer doesn't really fix the point I made my self... You need to both trim and remove double spaces with (for example) string.replace(/ +/g, " ").. Or you could split the el.className and then remove empty values with (for example) arr.filter(Boolean).
const classes = element.className.split(' ').filter(Boolean);
or more modern
const classes = element.classList;
Old:
With all the given answers, you should never forget to user .trim() (or $.trim())
Because classes gets added and removed, it can happen that there are multiple spaces between class string.. e.g. 'class1 class2 class3'..
This would turn into ['class1', 'class2','','','', 'class3']..
When you use trim, all multiple spaces get removed..
Might this can help you too. I have used this function to get classes of childern element..
function getClickClicked(){
var clickedElement=null;
var classes = null;<--- this is array
ELEMENT.on("click",function(e){//<-- where element can div,p span, or any id also a class
clickedElement = $(e.target);
classes = clickedElement.attr("class").split(" ");
for(var i = 0; i<classes.length;i++){
console.log(classes[i]);
}
e.preventDefault();
});
}
In your case you want doler_ipsum class u can do like this now calsses[2];.
Thanks for this - I was having a similar issue, as I'm trying to programatically relate objects will hierarchical class names, even though those names might not necessarily be known to my script.
In my script, I want an <a> tag to turn help text on/off by giving the <a> tag [some_class] plus the class of toggle, and then giving it's help text the class of [some_class]_toggle. This code is successfully finding the related elements using jQuery:
$("a.toggle").toggle(function(){toggleHelp($(this), false);}, function(){toggleHelp($(this), true);});
function toggleHelp(obj, mode){
var classList = obj.attr('class').split(/\s+/);
$.each( classList, function(index, item){
if (item.indexOf("_toggle") > 0) {
var targetClass = "." + item.replace("_toggle", "");
if(mode===false){$(targetClass).removeClass("off");}
else{$(targetClass).addClass("off");}
}
});
}
Try This. This will get you the names of all the classes from all the elements of document.
$(document).ready(function() {
var currentHtml="";
$('*').each(function() {
if ($(this).hasClass('') === false) {
var class_name = $(this).attr('class');
if (class_name.match(/\s/g)){
var newClasses= class_name.split(' ');
for (var i = 0; i <= newClasses.length - 1; i++) {
if (currentHtml.indexOf(newClasses[i]) <0) {
currentHtml += "."+newClasses[i]+"<br>{<br><br>}<br>"
}
}
}
else
{
if (currentHtml.indexOf(class_name) <0) {
currentHtml += "."+class_name+"<br>{<br><br>}<br>"
}
}
}
else
{
console.log("none");
}
});
$("#Test").html(currentHtml);
});
Here is the working example: https://jsfiddle.net/raju_sumit/2xu1ujoy/3/
For getting the list of classes applied to element we can use
$('#elementID').prop('classList')
For adding or removing any classes we can follow as below.
$('#elementID').prop('classList').add('yourClassName')
$('#elementID').prop('classList').remove('yourClassName')
And for simply checking if the class is present or not we can use hasClass
I had a similar issue, for an element of type image. I needed to check whether the element was of a certain class. First I tried with:
$('<img>').hasClass("nameOfMyClass");
but I got a nice "this function is not available for this element".
Then I inspected my element on the DOM explorer and I saw a very nice attribute that I could use: className. It contained the names of all the classes of my element separated by blank spaces.
$('img').className // it contains "class1 class2 class3"
Once you get this, just split the string as usual.
In my case this worked:
var listOfClassesOfMyElement= $('img').className.split(" ");
I am assuming this would work with other kinds of elements (besides img).
Hope it helps.
javascript provides a classList attribute for a node element in dom. Simply using
element.classList
will return a object of form
DOMTokenList {0: "class1", 1: "class2", 2: "class3", length: 3, item: function, contains: function, add: function, remove: function…}
The object has functions like contains, add, remove which you can use
A bit late, but using the extend() function lets you call "hasClass()" on any element, e.g.:
var hasClass = $('#divId').hasClass('someClass');
(function($) {
$.extend({
hasClass: new function(className) {
var classAttr = $J(this).attr('class');
if (classAttr != null && classAttr != undefined) {
var classList = classAttr.split(/\s+/);
for(var ix = 0, len = classList.length;ix < len;ix++) {
if (className === classList[ix]) {
return true;
}
}
}
return false;
}
}); })(jQuery);
The question is what Jquery is designed to do.
$('.dolor_spec').each(function(){ //do stuff
And why has no one given .find() as an answer?
$('div').find('.dolor_spec').each(function(){
..
});
There is also classList for non-IE browsers:
if element.classList.contains("dolor_spec") { //do stuff

Categories

Resources