How to check class of multiple class elements in javascript, without jquery - javascript

I have the following javascript code to put the uploader name before the upload date and view count in youtube search results.
function hasClass(element, cls) {
return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
var elems = document.getElementsByClassName('yt-lockup-meta-info');
var elemss = document.getElementsByClassName('yt-uix-sessionlink g-hovercard spf-link');
var elemsss = 1;
var elemssss = 0;
var myElem = document.getElementById('sb-button-notify');
if (myElem == null) elemsss = 0; // these two lines are here to skip the additional element
// that is only there if you are logged in
for (var i = 0; i < elems.length; ++i) {
if (hasClass(elemss[i+elemsss],'yt-uix-tile-link'))
{elemssss=elemssss+1;elemsss=elemsss+3;alert('damn');}
elems[i+elemssss].insertBefore(elemss[i+elemsss],elems[i+elemssss].firstChild);}
Instead of the hasClass function, how can I check the whole class attribute of a multiple class element? This didn't work:
element.className=='yt-uix-sessionlink yt-uix-tile-link
yt-ui-ellipsis yt-ui-ellipsis-2 g-hovercard spf-link'
I just need to check the class, so the code can skip elements with a specific class. An even better solution would be an alternative to document.getElementsByClassName, which would only get elements with exactly the given classes, and ignore ones that have MORE classes.

element.classList
It would return you the array of all the classes present on the element
like ["site-icon", "favicon", "favicon-stackoverflow"] , so then by using normal javascript you can implement hasClass functionality of your own.
So your hasClass function becomes
function hasClass(element, cls){
return element.classList.contains(cls);
}

You can use classList but this is not supported in all browsers.
I think the best solution is something like that:
function hasClass (element, cls) {
var classes = element.className.split(' ');
return classes.indexOf(cls) != -1;
}

Related

Javascript css selector for nested classes

I am creating a CSS selector for homework. I have managed to extract and get single selectors - e.g. #_id, but I cannot work out how to get a result for nested ones such as : div#_id._class [NOTE: I cannot use any libraries to do this or querySelectorAll]
The pseudo-code below is an example of what I currently have:
if (regex match for class) {
for (a in match for class) {
if (a.indexOf('.') > -1) {
var split_ = a.split(".");
var dot = split_[0];
var class_ = split_[1];
array_of_elements = document.getElementsByClassName(class_);
}
}
The problem is when the selector is nested I can't extract the whole thing using a similar method. E.g. look for an id, look for a class. Can anyone point me in the right direction?
else if (is id) {
split by ("#");
for (each result) {
if (has class ('.')) {
array_elements = document.getElementById(result_ID)
.getElementsByClassName(result_CLASS_NAME));
} else {
array_elements = (document.getElementsByTagName(result));
}
}
What you mentioned is actually called a sequence of simple selectors.
div#_id._class
It consitst of three simple selectors div, #_id, ._class
What you need to do is get elements by tag name, and then check for matches on all of the remaining simple selectors. I'll give you an idea here:
function qSelector(sequence) {
var tagName = getTag(sequence) || '*'; // 'div'
var ids = getIDs(sequence); // ['_id']
var classes = getClasses(sequence); // ['_class']
var els = document.getElementsByTagName(tagName);
return [].filter.call(els, function (el) {
for (id in ids) { if (el.id != id) return false; }
for (cls in classes) { if (el.className not contains cls) return false; }
return true;
});
}
This is more versatile than your approach and can be easily generalized to work with selectors containing spaces.
I'll leave the implementation of the get… helpers to you.

For cycle or for each with js objects

I got a problem to add a onclick event to object who can be many times in same page
I am trying to
var i;
for (i = 1; i<=10; i++) {
var tmpObj='lov_DgId_D_'+i;
var tmpObj2=tmpObj.getElementsByTagName('a')[0];
if (tmpObj2 != null) {
tmpObj2.onclick= DgIdOnClick;
}
}
But got a error TypeError:
Object lov_DgId_D_1 has no method 'getElementsByTagName' , but this is working
lov_DgId_D_2.getElementsByTagName('a')[0].onclick= DgIdOnClick;
This ibject lov_DgId_D_ can be from 1 like lov_DgId_D_1 or lov_DgId_D_99 u.t.c
What wil be the best solution to add onclick to all lov_DgId_D_* objects ?
As you use jquery, the simplest is
for (i = 1; i<=10; i++) {
$('#lov_DgId_D_'+ i+ ' a').click(DgIdOnClick);
}
If you want to bind your event handler to all a elements inside elements whose id starts with lov_DgId_D_, then it's as simple as
$('[id^="lov_DgId_D_"] a').click(DgIdOnClick);
The problem you have is a confusion between the id of an element and the actual element. Some code that should work for you is this one:
var i;
for (i = 1; i<=10; i++) {
var tmpObj=document.getElementById('lov_DgId_D_'+i); // <-- here
var tmpObj2=tmpObj.getElementsByTagName('a')[0];
if (tmpObj2 != null) {
tmpObj2.onclick= DgIdOnClick;
}
}
Slightly easier to read code:
for (var i=0; i<=10; i++) {
var anchor = document.querySelector('#lov_DgId_D_'+i + ' a');
if (anchor) anchor.onclick = DgIdOnClick;
}
A note: this code attaches a click event to the first anchor (a element) inside each element with the id lov_DgId_D_n, with n being 1->10. Your original code seems to want to do the same thing.
Another note: usually when you iterate over elements using their id's to identify them, you are better suited to add a class to those elements instead. It provides for more maintaintable code and probably easier to understand as well.

How to add additional class name to an element?

I can't believe I can't find this in google - I need to add an additional class name to a div with the classname checkField:
<div id="wth" class="checkField"><label>Ok whatever</label></div>
document.getElementById("wth").className="error"; // This works
document.getElementsByClassName("field").className="error"; // Doesn't work
I tried this:
document.getElementsByClassName("field").getElementsByTagName("label").className="error";
^ Also doesn't work.
Can someone please give me some advice? I'm too use to JQuery.
The getElementsByClassName method returns a nodeList, which is an array-like object, not a single element. To do what you want you need to iterate the list:
var divs = document.getElementsByClassName("checkField");
if (divs) {
// Run in reverse because we're
// modifying the result as we go:
for (var i=divs.length; i-- >= 0;) {
divs[i].className = 'error';
}
}
Also, just setting className actually replaces the class instead of adding to it. If you want to add another class you need to do it like this:
divs[i].className += ' error'; // notice the space bar
As for the second thing you're trying to do, that is setting the class of the label instead of the div, you need to loop through the divs and call getElementsByTagName on them:
var divs = document.getElementsByClassName("checkField");
if (divs) {
// Run in reverse because we're
// modifying the result as we go:
for (var i=divs.length; i-- >= 0;) {
var labels = divs[i].getElementsByTagName('label');
if (labels) {
for (var j=0; j<labels.length; j++) {
labels[j].className = 'error';
}
}
}
}
You need to add the class onto the current value:
document.body.className += " foo"; // adds foo class to body
Some browsers support classList which provides methods for adding, removing, and toggling classes on elements. For instance, you could add a new class like this:
document.body.classList.add("newClass");
Imagine the work involved in toggling a class; you'd have to perform some string operation to first determine whether a class is already on the element or not, and then respond accordingly. With classList you can just use the toggle method:
document.body.classList.toggle("toggleMe");
Some browsers don't currently support classList, but this won't prevent you from taking advantage of it. You can download a polyfill to add this feature where it's not natively supported.
try something like
you want to do this by document.body
so try
var demo =document.body;
// also do this by class like var demo = document.getElementsByClassName("div1one");
// or id var demo = document.getElementsId("div1one");
demo .className = demo .className + " otherclass";
or simpler solution if you have jquery as an option
$("body").addClass("yourClass");
Here's are simple utility functions for adding and removing a class:
function addClass(elem, cls) {
var oldCls = elem.className;
if (oldCls) {
oldCls += " ";
}
elem.className = oldCls + cls;
}
function removeClass(elem, cls) {
var str = " " + elem.className + " ";
elem.className = str.replace(" " + cls + " ", " ").replace(/^\s+|\s+$/g, "");
}

What is the best way to check if element has a class?

The problem
If the element has multiple classes then it will not match with the regular property value checking, so I'm looking for the best way to check if the object has a particular class in the element's className property.
Example
// element's classname is 'hello world helloworld'
var element = document.getElementById('element');
// this obviously fails
if(element.className == 'hello'){ ... }
// this is not good if the className is just 'helloworld' because it will match
if(element.className.indexOf('hello') != -1){ ... }
So what would be the best way to do this?
just pure javascript please
function hasClass( elem, klass ) {
return (" " + elem.className + " " ).indexOf( " "+klass+" " ) > -1;
}
In modern browsers, you can use classList:
if (element.classList.contains("hello")) {
// do something
}
In the browser that doesn't implement classList but exposes the DOM's prototype, you can use the shim showed in the link.
Otherwise, you can use the same shim's code to have a generic function without manipulate the prototype.
this 2018 use ES6
const hasClass = (el, className) => el.classList.contains(className);
How to use
hasClass(document.querySelector('div.active'), 'active'); // true
You ask for pure javascript, so this is how jQuery implement it:
hasClass: function( selector ) {
var className = " " + selector + " ",
i = 0,
l = this.length;
for ( ; i < l; i++ ) {
if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
return true;
}
}
return false;
},
rclass is a regular expression of [\n\t\r], to ensure that alternative methods of delimiting class names are not an issue. this would be jQuery's reference to the object(s) and in a sense it makes the code more complicated than required, but it should make sense without knowing the details of it.
This should work for you:
var a = [];
function getElementsByClassName(classname, node) {
if(!node) node = document.getElementsByTagName("body")[0];
var re = new RegExp('\\b' + classname + '\\b');
var els = node.getElementsByTagName("*");
for(var i=0, j=els.length; i<j; i++)
if(re.test(els[i].className)) a.push(els[i]);
return a;
}
getElementsByClassName('wrapper');
for (var i=0; i< a.length; i++) {
console.log(a[i].className);
}
This code will traverse the DOM and search for classes defined as parameter in the main function.Then it will test each founded class elements with a regexp pattern. If it founds will push to an array, and will output the results.
First, split the className by using the " " character, then check the index of the class you want to find.
function hasClass(element, clazz) {
return element.className.split(" ").indexOf(clazz) > -1;
}

Get a CSS value from external style sheet with Javascript/jQuery

Is it possible to get a value from the external CSS of a page if the element that the style refers to has not been generated yet? (the element is to be generated dynamically).
The jQuery method I've seen is $('element').css('property');, but this relies on element being on the page. Is there a way of finding out what the property is set to within the CSS rather than the computed style of an element?
Will I have to do something ugly like add a hidden copy of the element to my page so that I can access its style attributes?
With jQuery:
// Scoping function just to avoid creating a global
(function() {
var $p = $("<p></p>").hide().appendTo("body");
console.log($p.css("color"));
$p.remove();
})();
p {color: blue}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Using the DOM directly:
// Scoping function just to avoid creating a global
(function() {
var p = document.createElement('p');
document.body.appendChild(p);
console.log(getComputedStyle(p).color);
document.body.removeChild(p);
})();
p {color: blue}
Note: In both cases, if you're loading external style sheets, you'll want to wait for them to load in order to see their effect on the element. Neither jQuery's ready nor the DOM's DOMContentLoaded event does that, you'd have to ensure it by watching for them to load.
Normally you should be let the browser apply all the rules and then ask the browser for the results, but for the rare case where you really need to get the value out of the style sheet you can use this: (JSFiddle)
function getStyleSheetPropertyValue(selectorText, propertyName) {
// search backwards because the last match is more likely the right one
for (var s= document.styleSheets.length - 1; s >= 0; s--) {
var cssRules = document.styleSheets[s].cssRules ||
document.styleSheets[s].rules || []; // IE support
for (var c=0; c < cssRules.length; c++) {
if (cssRules[c].selectorText === selectorText)
return cssRules[c].style[propertyName];
}
}
return null;
}
alert(getStyleSheetPropertyValue("p", "color"));
Note that this is pretty fragile, as you have to supply the full selector text that matches the rule you are looking up (it is not parsed) and it does not handle duplicate entries or any kind of precedence rules. It's hard for me to think of a case when using this would be a good idea, but here it is just as an example.
In response to Karim79, I just thought I'd toss out my function version of that answer. I've had to do it several times so this is what I wrote:
function getClassStyles(parentElem, selector, style){
elemstr = '<div '+ selector +'></div>';
var $elem = $(elemstr).hide().appendTo(parentElem);
val = $elem.css(style);
$elem.remove();
return val;
}
val = getClassStyles('.container:first', 'class="title"', 'margin-top');
console.warn(val);
This example assumes you have and element with class="container" and you're looking for the margin-top style of the title class in that element. Of course change up to fit your needs.
In the stylesheet:
.container .title{ margin-top:num; }
Let me know what you think - Would you modify it, and if so how? Thanks!
I have written a helper function that accepts an object with the css attributes to be retrieved from the given css class and fills in the actual css attribute values.
Example is included.
function getStyleSheetValues(colScheme) {
var tags='';
var obj= colScheme;
// enumerate css classes from object
for (var prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop]=="object") {
tags+= '<span class="'+prop+'"></span>';
}
}
// generate an object that uses the given classes
tags= $('<div>'+tags+'</div>').hide().appendTo("body");
// read the class properties from the generated object
var idx= 0;
for (var prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop]=="object") {
var nobj= obj[prop];
for (var nprop in nobj) {
if (nobj.hasOwnProperty(nprop) && typeof(nobj[nprop])=="string") {
nobj[nprop]= tags.find("span:eq("+idx+")").css(nobj[nprop]);
}
}
idx++;
}
}
tags.remove();
}
// build an object with css class names where each class name contains one
// or more properties with an arbitrary name and the css attribute name as its value.
// This value will be replaced by the actual css value for the respective class.
var colorScheme= { chart_wall: {wallColor:'background-color',wallGrid:'color'}, chart_line1: { color:'color'} };
$(document).ready(function() {
getStyleSheetValues(colorScheme);
// debug: write the property values to the console;
if (window.console) {
var obj= colorScheme;
for (var prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop]=="object") {
var nobj= obj[prop];
for (var nprop in nobj) {
if (nobj.hasOwnProperty(nprop)) {
console.log(prop+'.'+nprop +':'+ nobj[nprop]);
}
}
}
}
// example of how to read an individual css attribute value
console.log('css value for chart_wall.wallGrid: '+colorScheme.chart_wall.wallGrid);
}
});
I wrote this js function, seems to be working for nested classes as well:
usage:
var style = get_css_property('.container-class .sub-container-class .child-class', 'margin');
console.log('style');
function get_css_property(class_name, property_name){
class_names = class_name.split(/\s+/);
var container = false;
var child_element = false;
for (var i = class_names.length - 1; i >= 0; i--) {
if(class_names[i].startsWith('.'))
class_names[i] = class_names[i].substring(1);
var new_element = $.parseHTML('<div class="' + class_names[i] + '"></div>');
if(!child_element)
child_element = new_element;
if(container)
$(new_element).append(container);
container = new_element;
}
$(container).hide().appendTo('body');
var style = $(child_element).css(property_name);
$(container).remove();
return style;
}

Categories