Process HTML in javascript - javascript

I would like to remove all instances of a .class in an html.
remove class "s"
remove <span class="s">some text</span> in html
Output
remove some text in html
What's the easiest way to do this?

Assuming you want to remove it from just this class. Here's how to keep just the text:
$(".s").each(function(){
$(this).replaceWith($(this).text());
});
Code in action.
And if you want to keep the HTML:
$(".s").each(function(){
$(this).replaceWith($(this).html());
});
And here's that code in action.

Here's a plain JavaScript solution. It might look a bit long at first sight, but it simply does what you want:
function moveElements(root) {
var parent = root.parentNode,
e = root.firstChild;
while (e != null) {
var next = e.nextSibling;
parent.insertBefore(e, root);
e = next;
}
parent.removeChild(root);
}
function removeClass(root, name) {
var e = root.firstChild;
while (e != null) {
var next = e.nextSibling;
if (e.nodeType == 1) { // element node
if (e.className == name)
moveElements(e); // move children outside this element
else
removeClass(e, name); // else recursively scan this element
}
e = next;
}
}
removeClass recursively scans elements looking for the specified class, and if found, calls moveElements, which moves the children outside and removes the original element. To run it through the entire document, removing the class s (from your example), call it like this:
removeClass(document.documentElement, 's');
Here's a working example on JSBin.

replaceNode?
http://www.webreference.com/js/column43/replace.html
The replaceNode method is much more intuitive than the removeNode method. While the removeNode method just removes the specified element and makes its descendents children of their grandfather, the replaceNode method deletes the whole subtree that is rooted at the specified element, and substitutes it with a new element.
var msg = "";
function printChildren() {
childCount = bodyNode.childNodes.length;
msg += "childCount = " + childCount;
for(var i = 0; i < childCount; i++) {
msg += "\nchildNodes["+i+"].nodeName = " + bodyNode.childNodes[i].nodeName;
}
}
printChildren();
msg += "\nReplacing Paragraph 3\n";
var b = document.createTextNode("New Body Page");
var replacedNode = p3Node.replaceNode(b);
msg += "\nreplacedNode.nodeName = " + replacedNode.nodeName;
msg += "\nreplacedNode.childNodes.length = " + replacedNode.childNodes.length;
msg += "\np2Node.nodeName = " + p2Node.nodeName;
printChildren();
alert(msg);

Using jQuery you could do:
$(".s").remove();
http://api.jquery.com/remove/

Related

Replace text in the middle of a TextNode with an element

I want to insert html tags within a text node with TreeWalker, but TreeWalker forces my html brackets into & lt; & gt; no matter what I've tried. Here is the code:
var text;
var tree = document.createTreeWalker(document.body,NodeFilter.SHOW_TEXT);
while (tree.nextNode()) {
text = tree.currentNode.nodeValue;
text = text.replace(/(\W)(\w+)/g, '$1<element onmouseover="sendWord(\'$2\')">$2</element>');
text = text.replace(/^(\w+)/, '<element onmouseover="sendWord(\'$1\')">$1</element>');
tree.currentNode.nodeValue = text;
}
Using \< or " instead of ' won't help. My workaround is to copy all of the DOM tree to a string and to replace the html body with that. It works on very simple webpages and solves my first problem, but is a bad hack and won't work on anything more than a trivial page. I was wondering if I could just work straight with the text node rather than use a workaround. Here is the code for the (currently buggy) workaround:
var text;
var newHTML = "";
var tree = document.createTreeWalker(document.body);
while (tree.nextNode()) {
text = tree.currentNode.nodeValue;
if (tree.currentNode.nodeType == 3){
text = text.replace(/(\W)(\w+)/g, '$1<element onmouseover="sendWord(\'$2\')">$2</element>');
text = text.replace(/^(\w+)/, '<element onmouseover="sendWord(\'$1\')">$1</element>');
}
newHTML += text
}
document.body.innerHTML = newHTML;
Edit: I realize a better workaround would be to custom tag the text nodes ((Customtag_Start_Here) etc.), copy the whole DOM to a string, and use my customs tags to identify text nodes and modify them that way. But if I don't have to, I'd rather not.
To 'change' a text node into an element, you must replace it with an element. For example:
var text = tree.currentNode;
var el = document.createElement('foo');
el.setAttribute('bar','yes');
text.parentNode.replaceChild( el, text );
If you want to retain part of the text node, and inject an element "in the middle", you need to create another text node and insert it and the element into the tree at the appropriate places in the tree.
Edit: Here's a function that might be super useful to you. :)
Given a text node, it runs a regex on the text values. For each hit that it finds it calls a custom function that you supply. If that function returns a string, then the match is replaced. However, if that function returns an object like:
{ name:"element", attrs{onmouseover:"sendWord('foo')"}, content:"foo" }
then it will split the text node around the match and inject an element in that location. You can also return an array of strings or those objects (and can recursively use arrays, strings, or objects as the content property).
Demo: http://jsfiddle.net/DpqGH/8/
function textNodeReplace(node,regex,handler) {
var mom=node.parentNode, nxt=node.nextSibling,
doc=node.ownerDocument, hits;
if (regex.global) {
while(node && (hits=regex.exec(node.nodeValue))){
regex.lastIndex = 0;
node=handleResult( node, hits, handler.apply(this,hits) );
}
} else if (hits=regex.exec(node.nodeValue))
handleResult( node, hits, handler.apply(this,hits) );
function handleResult(node,hits,results){
var orig = node.nodeValue;
node.nodeValue = orig.slice(0,hits.index);
[].concat(create(mom,results)).forEach(function(n){
mom.insertBefore(n,nxt);
});
var rest = orig.slice(hits.index+hits[0].length);
return rest && mom.insertBefore(doc.createTextNode(rest),nxt);
}
function create(el,o){
if (o.map) return o.map(function(v){ return create(el,v) });
else if (typeof o==='object') {
var e = doc.createElementNS(o.namespaceURI || el.namespaceURI,o.name);
if (o.attrs) for (var a in o.attrs) e.setAttribute(a,o.attrs[a]);
if (o.content) [].concat(create(e,o.content)).forEach(e.appendChild,e);
return e;
} else return doc.createTextNode(o+"");
}
}
It's not quite perfectly generic, as it does not support namespaces on attributes. But hopefully it's enough to get you going. :)
You would use it like so:
findAllTextNodes(document.body).forEach(function(textNode){
replaceTextNode( textNode, /\b\w+/g, function(match){
return {
name:'element',
attrs:{onmouseover:"sendWord('"+match[0]+"')"},
content:match[0]
};
});
});
function findAllTextNodes(node){
var walker = node.ownerDocument.createTreeWalker(node,NodeFilter.SHOW_TEXT);
var textNodes = [];
while (walker.nextNode())
if (walker.currentNode.parentNode.tagName!='SCRIPT')
textNodes.push(walker.currentNode);
return textNodes;
}
or if you want something closer to your original regex:
replaceTextNode( textNode, /(^|\W)(\w+)/g, function(match){
return [
match[1], // might be an empty string
{
name:'element',
attrs:{onmouseover:"sendWord('"+match[2]+"')"},
content:match[2]
}
];
});
Function that returns the parent element of any text node including partial match of passed string:
function findElByText(text, mainNode) {
let textEl = null;
const traverseNodes = function (n) {
if (textEl) {
return;
}
for (var nodes = n.childNodes, i = nodes.length; i--;) {
if (textEl) {
break;
}
var n = nodes[i], nodeType = n.nodeType;
// Its a text node, check if it matches string
if (nodeType == 3) {
if (n.textContent.includes(text)) {
textEl = n.parentElement;
break;
}
}
else if (nodeType == 1 || nodeType == 9 || nodeType == 11) {
traverseNodes(n);
}
}
}
traverseNodes(mainNode);
return textEl;
}
Usage:
findElByText('Some string in document', document.body);

Dynamic event attachment not working correctly [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
var smartActionsId = ['smartActions1','smartActions5','smartActions10'];
for (var i in smartActionsId) {
console.log("smartActionsId ="+smartActionsId[i]);
$('#' + smartActionsId[i] + ' select').change(function () {
var value = $(this).val();
var disableValue;
var ruleIndex = smartActionsId[i].substr(11);
console.log("smartActionsId ="+smartActionsId[i]+" i ="+i);
if (value === '0') {
disableValue = true;
onRuleToggle(disableValue, ruleIndex)
}
else if (value === '1') {
disableValue = false;
onRuleToggle(disableValue, ruleIndex)
}
});
}
I'm creating change event dynamically for a multiple switch slider items using the above JavaScript code. But problem I'm facing is, when I click on any switch 'i' value gets replaced with the last value i.e. in smartActionsId I have 3 elements, which ever switch I change it effects for last switch (smartActions10).
Could you please help me resolving this issue?
Other answers here fixed your problem, but I think you can refactor your code a little and make it much more understandable.
First, I don't like IDs. in your scenario, you have multiple ids which needs to be treated the same. Why not use one mighty class?
Also, ruleIndex calculated from element's ID? smells rotten.
If it tells you something about the element, it should be in an attribute or a data-* attribute.
The first bit of code fixes the markup by adding ruleIndex as data attribute and adding a .smart-actionable class. (Maybe you can even move this part to the server-side, to provide yourself with easier markup for JS).
Now, this makes the event handling quite simple.
var smartActionsId = ['smartActions1','smartActions5','smartActions10'];
for (var i in smartActionsId) {
$('#' + smartActionsId[i])
.data('ruleIndex', smartActionsId[i].substr(11))
.addClass('smart-actionable');
}
$('.smart-actionable').on('change', 'select', function() {
var value = $(this).val();
var disableValue = (value === '0');
onRuleToggle(disableValue, $(this).data('ruleIndex'));
});
Hope it will help.
You don't want to attach event listeners inside a for loop because the variable that tracks the index is used by each loop cycle. If you do that, the i variable will always equal the length of the array minus 1. Use Array.prototype.forEach() instead to prevent that.
var smartActionsId = ['smartActions1','smartActions5','smartActions10'];
smartActionsId.forEach(function (identifier, index) {
console.log("smartActionsId ="+identifier);
$('#' + smartActionsId[index] + ' select').change(function () {
var value = $(this).val();
var disableValue;
var ruleIndex = smartActionsId[index].substr(11);
console.log("smartActionsId ="+smartActionsId[index]+" index ="+index);
if (value === '0') {
disableValue = true;
onRuleToggle(disableValue, ruleIndex)
}
else if (value === '1') {
disableValue = false;
onRuleToggle(disableValue, ruleIndex)
}
});
});
Please Note: IE8 and down does NOT support Array.prototype.forEach().
You cant use for...in in this case. Please try the code below:
var smartActionsId = ['smartActions1', 'smartActions5', 'smartActions10'];
for (var i = 0; i < smartActionsId.length; i++) {
console.log("smartActionsId =" + smartActionsId[i]);
$('#' + smartActionsId[i] + ' select').change(function() {
var value = $(this).val();
var disableValue;
var ruleIndex = smartActionsId[i].substr(11);
console.log("smartActionsId =" + smartActionsId[i] + " i =" + i);
if (value === '0') {
disableValue = true;
onRuleToggle(disableValue, ruleIndex)
} else if (value === '1') {
disableValue = false;
onRuleToggle(disableValue, ruleIndex)
}
});
}
I've always use names like smartActions_1. If you can use it, then in your .change function you can use
// if 'smartActionsId' is global variable
// and if you need to get position in 'smartActionsId' array
var numInArray = $.inArray( this.parentNode.id, smartActionsId );
// this - your select DOM object
var ruleIndex = parseInt( this.parentNode.id.split( "_" )[ 1 ] );
And remember that this in .change function its select which have no id and you must use this.parentNode or $( this ).parent() to get it's holder (I think its div or somethink like that).
#Jack in comments is right: select may not be a direct child. Then you can use this code:
var parent = $( this ).closest( "[id^=smartActions]" );
var numInArray = $.inArray( parent.attr( "id" ), smartActionsId );
var ruleIndex = parseInt( parent.attr( "id" ).split( "_" )[ 1 ] );

Check if an element contains a class in JavaScript?

Using plain JavaScript (not jQuery), Is there any way to check if an element contains a class?
Currently, I'm doing this:
var test = document.getElementById("test");
var testClass = test.className;
switch (testClass) {
case "class1":
test.innerHTML = "I have class1";
break;
case "class2":
test.innerHTML = "I have class2";
break;
case "class3":
test.innerHTML = "I have class3";
break;
case "class4":
test.innerHTML = "I have class4";
break;
default:
test.innerHTML = "";
}
<div id="test" class="class1"></div>
The issue is that if I change the HTML to this...
<div id="test" class="class1 class5"></div>
...there's no longer an exact match, so I get the default output of nothing (""). But I still want the output to be I have class1 because the <div> still contains the .class1 class.
Use element.classList .contains method:
element.classList.contains(class);
This works on all current browsers and there are polyfills to support older browsers too.
Alternatively, if you work with older browsers and don't want to use polyfills to fix them, using indexOf is correct, but you have to tweak it a little:
function hasClass(element, className) {
return (' ' + element.className + ' ').indexOf(' ' + className+ ' ') > -1;
}
Otherwise you will also get true if the class you are looking for is part of another class name.
DEMO
jQuery uses a similar (if not the same) method.
Applied to the example:
As this does not work together with the switch statement, you could achieve the same effect with this code:
var test = document.getElementById("test"),
classes = ['class1', 'class2', 'class3', 'class4'];
test.innerHTML = "";
for(var i = 0, j = classes.length; i < j; i++) {
if(hasClass(test, classes[i])) {
test.innerHTML = "I have " + classes[i];
break;
}
}
It's also less redundant ;)
The easy and effective solution is trying .contains method.
test.classList.contains(testClass);
In modern browsers, you can just use the contains method of Element.classList :
testElement.classList.contains(className)
Demo
var testElement = document.getElementById('test');
console.log({
'main' : testElement.classList.contains('main'),
'cont' : testElement.classList.contains('cont'),
'content' : testElement.classList.contains('content'),
'main-cont' : testElement.classList.contains('main-cont'),
'main-content' : testElement.classList.contains('main-content'),
'main main-content' : testElement.classList.contains('main main-content')
});
<div id="test" class="main main-content content"></div>
Supported browsers
(from CanIUse.com)
Polyfill
If you want to use Element.classList but you also want to support older browsers, consider using this polyfill by Eli Grey.
Element.matches()
element.matches(selectorString)
According to MDN Web Docs:
The Element.matches() method returns true if the element would be selected by the specified selector string; otherwise, returns false.
Therefore, you can use Element.matches() to determine if an element contains a class.
const element = document.querySelector('#example');
console.log(element.matches('.foo')); // true
<div id="example" class="foo bar"></div>
View Browser Compatibility
This question is pretty solidly answered by element.classList.contains(), but people got pretty extravagant with their answers and made some bold claims, so I ran a benchmark.
Remember that each test is doing 1000 iterations, so most of these are still very fast. Unless you rely extensively on this for a specific operation, you won't see a performance difference.
I ran some tests with basically every way to do this. On my machine, (Win 10, 24gb, i7-8700), classList.contains performed super well. So did className.split(' ') which is effectively the same.
The winner though is classList.contains(). If you're not checking for classList to be undefined, ~(' ' + v.className + ' ').indexOf(' ' + classToFind + ' ') creeps ahead 5-15%
Since he wants to use switch(), I'm surprised no one has put this forth yet:
var test = document.getElementById("test");
var testClasses = test.className.split(" ");
test.innerHTML = "";
for(var i=0; i<testClasses.length; i++) {
switch(testClasses[i]) {
case "class1": test.innerHTML += "I have class1<br/>"; break;
case "class2": test.innerHTML += "I have class2<br/>"; break;
case "class3": test.innerHTML += "I have class3<br/>"; break;
case "class4": test.innerHTML += "I have class4<br/>"; break;
default: test.innerHTML += "(unknown class:" + testClasses[i] + ")<br/>";
}
}
Here is a little snippet If you’re trying to check wether element contains a class, without using jQuery.
function hasClass(element, className) {
return element.className && new RegExp("(^|\\s)" + className + "(\\s|$)").test(element.className);
}
This accounts for the fact that element might contain multiple class names separated by space.
OR
You can also assign this function to element prototype.
Element.prototype.hasClass = function(className) {
return this.className && new RegExp("(^|\\s)" + className + "(\\s|$)").test(this.className);
};
And trigger it like this (very similar to jQuery’s .hasClass() function):
document.getElementById('MyDiv').hasClass('active');
className is just a string so you can use the regular indexOf function to see if the list of classes contains another string.
This is a little old, but maybe someone will find my solution helpfull:
// Fix IE's indexOf Array
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement) {
if (this == null) throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (len === 0) return -1;
var n = 0;
if (arguments.length > 0) {
n = Number(arguments[1]);
if (n != n) n = 0;
else if (n != 0 && n != Infinity && n != -Infinity) n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
if (n >= len) return -1;
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
for (; k < len; k++) if (k in t && t[k] === searchElement) return k;
return -1;
}
}
// add hasClass support
if (!Element.prototype.hasClass) {
Element.prototype.hasClass = function (classname) {
if (this == null) throw new TypeError();
return this.className.split(' ').indexOf(classname) === -1 ? false : true;
}
}
A simplified oneliner:1
function hasClassName(classname,id) {
return String ( ( document.getElementById(id)||{} ) .className )
.split(/\s/)
.indexOf(classname) >= 0;
}
1 indexOf for arrays is not supported by IE (ofcourse). There are plenty of monkey patches to be found on the net for that.
I know there a lot of answers but most of these are for additional functions and additional classes. This is the one I personally use; much cleaner and much less lines of code!
if( document.body.className.match('category-page') ) {
console.log('yes');
}
I've created a prototype method which uses classList, if possible, else resorts to indexOf:
Element.prototype.hasClass = Element.prototype.hasClass ||
function(classArr){
var hasClass = 0,
className = this.getAttribute('class');
if( this == null || !classArr || !className ) return false;
if( !(classArr instanceof Array) )
classArr = classArr.split(' ');
for( var i in classArr )
// this.classList.contains(classArr[i]) // for modern browsers
if( className.split(classArr[i]).length > 1 )
hasClass++;
return hasClass == classArr.length;
};
///////////////////////////////
// TESTS (see browser's console when inspecting the output)
var elm1 = document.querySelector('p');
var elm2 = document.querySelector('b');
var elm3 = elm1.firstChild; // textNode
var elm4 = document.querySelector('text'); // SVG text
console.log( elm1, ' has class "a": ', elm1.hasClass('a') );
console.log( elm1, ' has class "b": ', elm1.hasClass('b') );
console.log( elm1, ' has class "c": ', elm1.hasClass('c') );
console.log( elm1, ' has class "d": ', elm1.hasClass('d') );
console.log( elm1, ' has class "a c": ', elm1.hasClass('a c') );
console.log( elm1, ' has class "a d": ', elm1.hasClass('a d') );
console.log( elm1, ' has class "": ', elm1.hasClass('') );
console.log( elm2, ' has class "a": ', elm2.hasClass('a') );
// console.log( elm3, ' has class "a": ', elm3.hasClass('a') );
console.log( elm4, ' has class "a": ', elm4.hasClass('a') );
<p class='a b c'>This is a <b>test</b> string</p>
<svg xmlns="http://www.w3.org/2000/svg" width="100px" height="50px">
<text x="10" y="20" class='a'>SVG Text Example</text>
</svg>
Test page
Here's a case-insensitive trivial solution:
function hasClass(element, classNameToTestFor) {
var classNames = element.className.split(' ');
for (var i = 0; i < classNames.length; i++) {
if (classNames[i].toLowerCase() == classNameToTestFor.toLowerCase()) {
return true;
}
}
return false;
}
Felix's trick of adding spaces to flank the className and the string you're searching for is the right approach to determining whether the elements has the class or not.
To have different behaviour according to the class, you may use function references, or functions, within a map:
function fn1(element){ /* code for element with class1 */ }
function fn2(element){ /* code for element with class2 */ }
function fn2(element){ /* code for element with class3 */ }
var fns={'class1': fn1, 'class2': fn2, 'class3': fn3};
for(var i in fns) {
if(hasClass(test, i)) {
fns[i](test);
}
}
for(var i in fns) iterates through the keys within the fns map.
Having no break after fnsi allows the code to be executed whenever there is a match - so that if the element has, f.i., class1 and class2, both fn1 and fn2 will be executed.
The advantage of this approach is that the code to execute for each class is arbitrary, like the one in the switch statement; in your example all the cases performed a similar operation, but tomorrow you may need to do different things for each.
You may simulate the default case by having a status variable telling whether a match was found in the loop or not.
If the element only has one class name you can quickly check it by getting the class attribute. The other answers are much more robust but this certainly has it's use cases.
if ( element.getAttribute('class') === 'classname' ) {
}
See this Codepen link for faster and easy way of checking an element if it has a specific class using vanilla JavaScript~!
hasClass (Vanilla JS)
function hasClass(element, cls) {
return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
This is supported on IE8+.
First we check if classList exists if it does we can use the contains method which is supported by IE10+. If we are on IE9 or 8 it falls back to using a regex, which is not as efficient but is a concise polyfill.
if (el.classList) {
el.classList.contains(className);
} else {
new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
}
Alternatively if you are compiling with babel you can simply use:
el.classList.contains(className);
To check if an element contains a class, you use the contains() method of the classList property of the element:*
element.classList.contains(className);
*Suppose you have the following element:
<div class="secondary info">Item</div>*
To check if the element contains the secondary class, you use the following code:
const div = document.querySelector('div');
div.classList.contains('secondary'); // true
The following returns false because the element doesn’t have the class error:
const div = document.querySelector('div');
div.classList.contains('error'); // false
I think that perfect solution will be this
if ($(this).hasClass("your_Class"))
alert("positive");
else
alert("Negative");
I would Poly fill the classList functionality and use the new syntax. This way newer browser will use the new implementation (which is much faster) and only old browsers will take the performance hit from the code.
https://github.com/remy/polyfills/blob/master/classList.js
This is a bit off, but if you have an event that triggers switch, you can do without classes:
<div id="classOne1"></div>
<div id="classOne2"></div>
<div id="classTwo3"></div>
You can do
$('body').click( function() {
switch ( this.id.replace(/[0-9]/g, '') ) {
case 'classOne': this.innerHTML = "I have classOne"; break;
case 'classTwo': this.innerHTML = "I have classTwo"; break;
default: this.innerHTML = "";
}
});
.replace(/[0-9]/g, '') removes digits from id.
It is a bit hacky, but works for long switches without extra functions or loops
As the accepted answer suggests, Element.className returns a string, so you can easily check if a class exists by using the indexOf() method:
element.className.indexOf('animated') > -1
If you are interested in the performance difference between indexOf vs classList.contains, using indexOf seems to be slightly faster. I did a quick benchmark performance test to check that. Here are my findings: ClassName.indexOf vs ClassList.contains.
Try this one:
document.getElementsByClassName = function(cl) {
var retnode = [];
var myclass = new RegExp('\\b'+cl+'\\b');
var elem = this.getElementsByTagName('*');
for (var i = 0; i < elem.length; i++) {
var classes = elem[i].className;
if (myclass.test(classes)) retnode.push(elem[i]);
}
return retnode;
};
in which element is currently the class '.bar' ? Here is another solution but it's up to you.
var reg = /Image/g, // regexp for an image element
query = document.querySelector('.bar'); // returns [object HTMLImageElement]
query += this.toString(); // turns object into a string
if (query.match(reg)) { // checks if it matches
alert('the class .bar is attached to the following Element:\n' + query);
}
jsfiddle demo
Of course this is only a lookup for 1 simple element <img>(/Image/g) but you can put all in an array like <li> is /LI/g, <ul> = /UL/g etc.
Just to add to the answer for people trying to find class names within inline SVG elements.
Change the hasCLass() function to:
function hasClass(element, cls) {
return (' ' + element.getAttribute('class') + ' ').indexOf(' ' + cls + ' ') > -1;
}
Instead of using the className property you'll need to use the getAttribute() method to grab the class name.
I created these functions for my website, I use only vanilla javascript, maybe it will help someone.
First I created a function to get any HTML element:
//return an HTML element by ID, class or tag name
var getElement = function(selector) {
var elements = [];
if(selector[0] == '#') {
elements.push(document.getElementById(selector.substring(1, selector.length)));
} else if(selector[0] == '.') {
elements = document.getElementsByClassName(selector.substring(1, selector.length));
} else {
elements = document.getElementsByTagName(selector);
}
return elements;
}
Then the function that recieve the class to remove and the selector of the element:
var hasClass = function(selector, _class) {
var elements = getElement(selector);
var contains = false;
for (let index = 0; index < elements.length; index++) {
const curElement = elements[index];
if(curElement.classList.contains(_class)) {
contains = true;
break;
}
}
return contains;
}
Now you can use it like this:
hasClass('body', 'gray')
hasClass('#like', 'green')
hasClass('.button', 'active')
Hope it will help.
Tip: Try to remove dependencies of jQuery in your projects as much as you can - VanillaJS.
document.firstElementChild returns <html> tag then the classList attribute returns all classes added to it.
if(document.firstElementChild.classList.contains("your-class")){
// <html> has 'your-class'
} else {
// <html> doesn't have 'your-class'
}
Since .className is a string, you can use the string includes() method to check if your .className includes your class name:
element.className.includes("class1")
Using the classList is also ideal
HTML
<div id="box" class="myClass"></div>
JavaScript
const element = document.querySelector("#box");
element.classList.contains("myClass");
For me the most elegant and faster way to achieve it is:
function hasClass(el, cl) {
return el.classList ? el.classList.contains(cl) : !!el.className && !!el.className.match(new RegExp('(?: |^)' + cl + '(?: |$)'));
}

javascript: getElementsByClass

Im looking to do something simple and the site is not heavy with js so im not using a js framework for this.
I am trying to add event click listener, I am trying to get element by class. I found the following function + others that I have tried but for some reason none of them are finding the elements.
function getElementsByClass( searchClass, domNode, tagName) {
if (domNode == null) domNode = document;
if (tagName == null) tagName = '*';
var el = new Array();
var tags = domNode.getElementsByTagName(tagName);
var tcl = " "+searchClass+" ";
for(i=0,j=0; i<tags.length; i++) {
var test = " " + tags[i].className + " ";
if (test.indexOf(tcl) != -1)
el[j++] = tags[i];
}
return el;
}
var els = getElementsByClass("wow");
alert(els.length);
i have a couple of divs with the class wow, testing but I keep getting 0.
Assuming your function works properly, do it when the DOM is ready or on window load. Or call it before the end body tag.
DEMO: http://jsfiddle.net/rXApk/
The class attribute takes a space separated list of class names, not a comma separated list.
Your test won't match wow, as it looks for wow.

What's the best way to strip out only the anchor HTML tags in javascript, given a string of html?

Let's say there's a string of HTML, with script tags, plain text, whatever.
What's the best way to strip out only the <a> tags?
I've been using some methods here, but these are for all tags. Strip HTML from Text JavaScript
Using jQuery:
var content = $('<div>' + htmlString + '</div>');
content.find('a').replaceWith(function() { return this.childNodes; });
var newHtml = content.html();
Adding a wrapping <div> tag allows us to get the desired HTML back.
I wrote a more detailed explanation on my blog.
This approach will preserve existing DOM nodes, minimizing side-effects if you have elements within the anchors that have events attached to them.
function unwrapAnchors() {
if(!('tagName' in this) || this.tagName.toLowerCase() != 'a' || !('parentNode' in this)) {
return;
}
var childNodes = this.childNodes || [], children = [], child;
// Convert childNodes collection to array
for(var i = 0, childNodes = this.childNodes || []; i < childNodes.length; i++) {
children[i] = childNodes[i];
}
// Move children outside element
for(i = 0; i < children.length; i++) {
child = children[i];
if(('tagName' in child) && child.tagName.toLowerCase() == 'a') {
child.parentNode.removeChild(child);
} else {
this.parentNode.insertBefore(child, this);
}
}
// Remove now-empty anchor
this.parentNode.removeChild(this);
}
To use (with jQuery):
$('a').each(unwrapAnchors);
To use (without jQuery):
var a = document.getElementsByTagName('a');
while(a.length) {
unwrapAnchors.call(a[a.length - 1]);
}
A <a> tag is not supposed to hold any other <a> tag, so a simple ungreedy regexp would do the trick (i.e. string.match(/<a>(.*?)<\/a>/), but this example suppose the tags have no attribute).
Here's a native (non-library) solution if performance is a concern.
function stripTag(str, tag) {
var a, parent, div = document.createElement('div');
div.innerHTML = str;
a = div.getElementsByTagName( tag );
while( a[0] ) {
parent = a[0].parentNode;
while (a[0].firstChild) {
parent.insertBefore(a[0].firstChild, a[0]);
}
parent.removeChild(a[0]);
}
return div.innerHTML;
}
Use it like this:
alert( stripTag( my_string, 'a' ) );

Categories

Resources