How to get individual element's CSS selector/Xpath - javascript

What I am trying to accomplish is basically, to get a list of Elements ( currently using document.querySelectorAll() in order to get a list of elements using a general selector.
E.g: get me all elements of .note class in the document.
document.querySelectorAll('.note')
since it collects them from all over the DOM, I then need a JS function to iterate over all of them using a different function from a library that does not use NodeList, and I need it to query all these elements individually (This is an automation task so negligent benefits of speed are of no matter here).
Since these elements appear on different parts and hierarchies of the DOM, I cannot fetch them all with a CSS selector individually like :nth-of-type, I need the specific CSS Selector/ XPath of each of them.
For example, for all .note class elements on a page, I need the result to be something like:
['.my-first-class .inner .note', 'section .different-class .inner .note', '.profile .profile-notes .note']
something in this style would be extremely helpful to me.
Thank you very much for any assistance you may provide!

I borrowed a generateQuerySelector function from this answer and simply looped over the results of .note query selection, being sure to convert the NodeList to an Array.
const notes = Array.from(document.querySelectorAll('.note'))
notes.forEach(note => {
console.log(generateQuerySelector(note))
})
function generateQuerySelector (el) {
if (el.tagName.toLowerCase() == "html")
return "HTML";
var str = el.tagName;
str += (el.id != "") ? "#" + el.id : "";
if (el.className) {
var classes = el.className.split(/\s/);
for (var i = 0; i < classes.length; i++) {
str += "." + classes[i]
}
}
return generateQuerySelector(el.parentNode) + " > " + str;
}
<div class="content">
<div class="primary">
<div class="article">
<div class="note">
</div>
</div>
</div>
<div class="secondary">
<div class="aside">
<div class="note">
</div>
</div>
</div>
<div class="note">
</div>
<div id="contact-form">
<div class="note"></div>
</div>
</div>

Css can't write it down, it can only show you whatever you want in the way you want
body *{ display: block} /* only if you want single column */
.wanted::after{ content: ' wanted '; float: right; background: red; color: #000; margin: 0 5px; padding: 0 5px}
p.wanted::after{ content: 'I am a <p>'; background: #cf8;}
div.wanted::after{ content: 'I am a <div>'; background: yellow}
a.wanted::after{ content: 'href me';background: orange}
<div>div</div>
link
<p>paragraph</p>
<a class="wanted">link</a>
link
<div>div</div>
<div class="wanted">div</div>
link
<a class="wanted">link</a>
<nav class="wanted">nav</nav>
<div class="wanted"> div </div>
<div>div</div>
<p>paragraph</p>
<div class="wanted"> div </div>
<p class="wanted">paragraph</p>
link
<div class="wanted"> div </div>
<a class="wanted">link</a>
<a class="wanted">link</a>
<div class="wanted"> div </div>
<p class="wanted">paragraph</p>
<div>div</div>
<div class="wanted"> div </div>
link
<div class="wanted"> div </div>
<p class="wanted">paragraph</p>
<div>div</div>
<a class="wanted">link</a>
<div class="wanted"> div </div>
<div>div</div>
<p>paragraph</p>
<div class="wanted"> div </div>
<div>div</div>
<p class="wanted">paragraph</p>
link
<a class="wanted">link</a>
<div>div</div>

Related

javascript/jquery - How to take variable of child class name from repeated occurrences of parent class

EDIT (old link to JSFiddle was wrong): Link to JSFiddle example: https://jsfiddle.net/uvexys0a/
I am attempting to program in jQuery so it wraps an HTML link to the staff member's profile page wraps around the entire each div with the class name staffList. The path to the page is stored as a child class in each div, as seen on the JSFiddle.
The code seems to function, somewhat. Both links end up going to John Smith's profile:
<a href="https://example.com/john-smith">
<div class="staffList john-smith">
<p>John Smith</p>
<p>Co-Founder</p>
</div>
</a>
<a href="https://example.com/john-smith">
<div class="staffList jane-smith">
<p>Jane Smith</p>
<p>Co-Founder</p>
</div>
</a>
However, if the code was running properly, it would output like this:
<a href="https://example.com/john-smith">
<div class="staffList john-smith">
<p>John Smith</p>
<p>Co-Founder</p>
</div>
</a>
<a href="https://example.com/jane-smith">
<div class="staffList jane-smith">
<p>Jane Smith</p>
<p>Co-Founder</p>
</div>
</a>
How do you code so the variable staffURL changes with each repeated parent div with parent class staffList and the child class the corresponding staff member's link?
You're basing your links off of the second class name, but in your second staffList, you say John Smith again, so you get john-smith both times for each link. You can change that to jane-smith and loop over each item to get what you want. Try this:
jQuery(function($){
var staffList = $(".staffList");
$.each(staffList, function(i) {
var staffURL = $(this).attr('class').split(' ')[1];
$(staffList[i]).wrap("<a href='https://example.com/"+staffURL+"/'></a>");
});
});
.staffList {
border: 1px solid #000;
margin: 15px;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container">
<div id="warpper">
<div id="staffSection">
<div class="staffList john-smith">
<p>John Smith</p>
<p>Co-Founder</p>
</div>
<div class="staffList jane-smith">
<p>Jane Smith</p>
<p>Co-Founder</p>
</div>
</div>
</div>
</div>
jsfiddle: https://jsfiddle.net/7nxbu1t5/2/
You'd need to loop through each staffList item in order to set the URL dynamically.
jQuery(function($) {
/**
* Loop through each list item
*/
$('.staffList').each(function() {
var $listItem = $(this);
var staffSlug = $listItem
.attr('class') // Get the value of the class attribute
.replace('staffList', '') // Remove the common class
.trim(); // Clear up any pre/appending white space
// Wrap element in `a` tag
$listItem.wrap('');
});
});
.staffList {
border: 1px solid #000;
margin: 15px;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container">
<div id="warpper">
<div id="staffSection">
<div class="staffList john-smith">
<p>John Smith</p>
<p>Co-Founder</p>
</div>
<div class="staffList jane-smith">
<p>Jane Smith</p>
<p>Co-Founder</p>
</div>
</div>
</div>
</div>

How to add a class to element if another element is empty?

I am trying to remove the existing class (blue) and add a new class (red) to the <'h2'> when the <'a'> is empty.
<div id="heading" class="header">
<h2 id="title" class="blue">Header text goes here</h2>
<a class="info" href="#"></a>
</div>
<style>
.blue{color:blue}
.red{color:red}
</style>
I have tried a few variations but without success. This is my latest.
$("#heading a.info:empty").removeClass('blue').addClass("red");
Any help on this would be appreciated.
Use .text() to find if it is empty
var a =$(".info").text().trim();
a===""?($("#title").removeClass("blue").addClass('red')):''
JSFIDDLE
if($("#heading a.info").text() === ''){
$("#heading h2").removeClass('blue').addClass("red");
}
.blue{color:blue}
.red{color:red}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="heading" class="header">
<h2 id="title" class="blue">Header text goes here</h2>
<a class="info" href="#"></a>
</div>
if ($("#heading a.info:empty")) {
$("#title").removeClass('blue').addClass("red");
}
.blue {
color: blue
}
.red {
color: red
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="heading" class="header">
<h2 id="title" class="blue">Header text goes here</h2>
<a class="info" href="#"></a>
</div>
Should remove from h2 not from anchor
:empty returns a collection of elements. And you need to add/remove class from h2,
so use .prev() to get the previous sibling.
$("#heading a.info:empty")
.prev('#title')
.removeClass('blue')
.addClass("red");

<a> element not working properly when hiding parent?

I made this script, and despite one oddity, it works fine. It's hiding/showing the parent of div element with a class containing specific content. The problem when I press my <a> elements, that act as buttons, they "filter" the divs, but it leaves the first comment <a>? If I change the element do a <div> instead no problem, but with an <a> element it behaves weirdly? Is this just a bug or?
here is a JSFiddle: https://jsfiddle.net/g1puxhs7/2/
HTML:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js">
</script>
<a class='viewBtn'>Published<a>
<a class='viewBtn'>Completed<a>
<a class='viewBtn'>Created<a>
<div class="orders" id="orders">
<div class="row">
<div class="status">
Completed
</div>
<a>Comment</a>
</div>
<div class="row">
<div class="status">
Completed
</div>
<a>Comment</a>
</div>
<div class="row">
<div class="status">
Completed
</div>
<a>Comment</a>
</div>
</div>
<style>
.row {
width: 200px;
margin: 10px;
background: #ccc;
padding: 4px;
}
</style>
SCRIPT:
//--Filter by Status--//
$('.viewBtn').click(function() {
var txt = $(this).text();
$('.status:contains("' + txt + '")').parent().toggle();
$(this).toggleClass('down');
});
The problem is with your links:
<a class='viewBtn'>Published<a>
<a class='viewBtn'>Completed<a>
<a class='viewBtn'>Created<a>
You have 6 opening a tags, instead of 3 opening and 3 closing tags.
This is why the browser adds closing a tags in your script in a bunch of places, one of them in your first div—and then your whole DOM tree looks different than what you want.
Your markup needed to be cleaned up. Here is your markup cleaned up. Also, i find it best to add href for you anchor tags, and then you can comment them out with #, or you can add javascript:void(0). If you use the # approach, in your JS, you can add e.preventDefault();
HTML Cleaned:
<div>
<a class='viewBtn' href="#">Published</a>
<a class='viewBtn' href="#">Completed</a>
<a class='viewBtn' href="#">Created</a>
</div>
<div class="orders" id="orders">
<div class="row">
<div class="status">
Completed
</div>
<a class="stuff" onclick="Comment">Comment</a>
</div>
<div class="row">
<div class="status">
Completed
</div>
<a class="stuff">Comment</a>
</div>
<div class="row">
<div class="status">
Completed
</div>
<a class="stuff">Comment</a>
</div>
</div>
JS with preventDefault():
$('.viewBtn').click(function(e) {
e.preventDefault();
var txt = $(this).text();
$('.status:contains("' + txt + '")').parent().toggle();
$(this).toggleClass('down');
});

How can I find IDs of DIVS, and assign those names as classes to other DIVS?

I'm fairly new to jquery and cannot figure this out. I have 3 divs with different id's but all start with "sharedform". I want to loop through those divs, grab each id and assign it as an identifying class to the 'slideHead' div preceding each. Any help would be greatly appreciated!
HMTL:
<div class="slideHead">
</div>
<div class="drawer">
<div id="sharedform.upload_image">
<p></p>
</div>
</div>
<div class="slideHead">
</div>
<div class="drawer">
<div id="sharedform.Event">
<p></p>
</div>
</div>
<div class="slideHead">
</div>
<div class="drawer">
<div id="sharedform.BackGround_All">
<p></p>
</div>
</div>
jquery:
var $getclass = $(".drawer");
addclass = $getclass.find('[id^="sharedform"]').attr('id');
$(".slideHead").addClass(addclass);
I'd suggest:
// get all elements whose id starts with 'sharedform', iterate over that collection:
$('div[id^=sharedform]').each(function (){
// find the parent of the 'this' element:
$(this).parent()
// find the previous element, if it matches the passed-in selector:
.prev('.slideHead')
// add the id of the element we initially selected as a class:
.addClass(this.id);
});
$('div[id^=sharedform]').each(function() {
$(this).parent().prev('.slideHead').addClass(this.id);
});
div {
width: 80%;
margin: 0 auto;
min-height: 2em;
padding: 0.5em;
border: 1px solid #000;
}
.slideHead {
background-color: #f00;
}
.slideHead.sharedform\.something {
background-color: #0f0;
}
<div class="slideHead"></div>
<div>
<div id="sharedform.something">some text in the div</div>
</div>
But note that those class-names are problematic, given the inclusion of a period (.) in the id.
This should do it:
$('[id^=sharedform]').each(function() {
$(this).closest('.drawer').prev().addClass( this.id );
});
$('[id^=sharedform]').each(function() {
$(this).closest('.drawer').prev().addClass( this.id );
});
var newHTML = $('body').html(),
out = $('<pre/>', {class:'out'}).appendTo( 'body' );
out.text( 'NEW HTML\n' + newHTML );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="slideHead">
</div>
<div class="drawer">
<div id="sharedform.upload_image">
<p></p>
</div>
</div>
<div class="slideHead">
</div>
<div class="drawer">
<div id="sharedform.Event">
<p></p>
</div>
</div>
<div class="slideHead">
</div>
<div class="drawer">
<div id="sharedform.BackGround_All">
<p></p>
</div>
</div>

Show/Hide Image DIV

I want the image to act as a toggle so when it's clicked on it will reveal the div with the text.
Here's the CSS class I'm using:
.hidden { display: none; }
.unhidden { display: block; }
and the JS:
function unhide(divID) {
var item = document.getElementById(divID);
if (item) {
item.className=(item.className=='hidden')?'unhidden':'hidden';
}
}//
Here's the HTML:
<div class="4u">
<!-- Box -->
<section class="box box-feature">
<a href="javascript:unhide('test');" class="image image-full"
<img src="images/pic01.jpg" alt="" /></a>
<div id="test" class="hidden">
<header>
<h2>Put something here</h2>
<span class="byline">Maybe here as well I think</span>
</header>
<p>Test and more text and more text and more text.</p>
</div>
</section>
</div>
You have a syntax error. Change line 4 to:
<a href="javascript:unhide('test');" class="image image-full">
Note the > at the end of the line.
Unless you're determined to use vanilla JavaScript, a much easier way would be to use jQuery. Add this to your <head>:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
And then your a href could be just javascript:$('#test').toggle() and you wouldn't need to define any functions or CSS classes.

Categories