Using jQuery to find a html element in a parallel tree path - javascript

Let's say I have this piece of html:
<div>
<a class="target"/>
<div>
<a class="target"/>
<div>
<hr class="source"/>
</div>
</div>
</div>
I'd like to find the closest target from the source, meaning the one where I need to climb the fewest amount of parents. With a binding, I get the source element, that I'll note source. I want to find the second anchor, which is two levels deep, as it's closer to my source hr.
Here's what I have right now is, which works:
var target = source
.parentsUntil(".target").eq(0)
.find(".target")[0];
It seems rather uneffective though, because parentsUntil will test and return too many of the parents. I'd like it to stop on the first parent containing a .target element. Then I feel like calling find after makes jQuery look for target once more while it had already found it before with parentsUntil.
I can think of another solution that would involve iterating over source.parents() and calling find until I have a result but that would still search into branches that have already been explored.
Is there a function in jQuery or a custom algorithm I could leverage to get my result by exploring only the part of the tree that needs to be explored?

I'd suggest:
// starts at the element(s) with the class of
// 'source':
$('.source')
// finds the closest <div> element that contains
// an <a> element with the class-name of 'target':
.closest('div:has("a.target")')
// finds that contained <a> element with
// the class of 'target':
.find('a.target');
$('.source').closest('div:has("a.target")').find('a.target').addClass('found');
a::before {
content: attr(class);
}
.found {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<a class="target"></a>
<div>
<a class="target"></a>
<div>
<hr class="source" />
</div>
</div>
</div>
References:
addClass().
closest().
find().
:has() selector.

In your case you can use .parent() to select the parent div of .source element and use .prev() to get the previous element which is <a> in your case
$('.source').parent().prev()
or you can use
$('.source').parent().parent().find('a.target')

Related

querySelectorAll to include self

<div class="a">
<span class="a">a</span>
<span class="a">b</span>
<span class="a">c</span>
</div>
Assuming I have a variable called divA representing the top level div node. divA.querySelectorAll('.a') will return a list of the 3 span.as. I wonder if there's an easy way to return a list of 4 elements including the divA itself?
I know I could start from a higher level node, but let's assume there might be other .a elements that I don't want to mess with them.
In reality I still need to test whether divA matches my selector or not. So is there a way for css selector to test an element itself?
I could create a parent node and run querySelectorAll from there. But if there's an easier way, I don't need to go that far.
I still need to test whether divA matches my selector or not. Is there
a way for css selector to test an element itself?
querySelector() cannot return the context element it's running on.
What you can do is use #Andreas' solution followed by a filter()/matches() combo.
[divA, ...divA.querySelectorAll('.a')].filter(el => el.matches('.a'));
This is what you're looking for I guess: :scope
EDIT:
Just like in this answer: https://stackoverflow.com/a/43354126/14034888
const parent = document.querySelector('.parent');
console.log(parent.querySelectorAll(':scope .box'));
should return (if it exists in the DOM of course) a NodeList of length 5 with .parent as the first element in the list and the children (and grand children) filling the remaining four indices...
<div class='parent box'>
<div class='box'></div>
<div class='box'>
<div class='inner box'></div>
</div>
<div class='box'></div>
</div>

How do I access a sub-element when using $(this) in jQuery

I have the following code:
$(document).ready(function(){
$(document).on('click', '.mydiv', function(){
console.log(??????);
});
});
I also have the corresponding html
<div class="mydiv">
<p>Hello from inside a mydiv</p>
</div>
<div class="mydiv">
<p>Hello from inside some other mydiv</p>
</div>
My goal is to print the text inside the p tags to the console when the I click on any div with the class of mydiv. I know that this means I should be using the $(this) operator, but when I do that I am unsure of how to then access its sub elements.
I know if I were using id's (or if I only had one of these class objects) I could simply do $('#mydiv p').val(), but I'm unsure of how to achieve this when I'm using $(this).
You can use $('p',this) or $(this).find('p') to get p tag element in this context:
$(document).on('click', '.mydiv', function(){
console.log($('p',this).text());
});
Working Demo
Using $(this) and jQuery's .find() you can get the child elements that you choose:
console.log($(this).find('p').html());
There are multiple ways to go about this. One of the ways has been mentioned here by others (the find method). The problem with the find method is that it finds all elements inside your div and not the direct children. So, if you have elements that are nested another level, it gets that as well.
With the children method, it will find the direct child of the element, but not anything nested deeper.
<div class="mydiv">
<div>
<p>Nested p</p>
</div>
</div>
$('.mydiv').find('p'); // Finds this element, but children() will not
Versus
<div class="mydiv">
<p>
Direct p
</p>
</div>
$('.mydiv').children('p'); // Will find this element, but find() will as well
With the find method, you will find the one nested inside the second div, whilst with the children method, you will find only the direct child.
Depending on your needs, you may use find or children

CasperJS Click on all links matching a selector

I have read this question and its answer, and wish to take it a little bit further.
I want to use CasperJS.click(selector) function to click multiple links matching a selector. Please note that the links do not have a significant href tag.
Consider the following markup:
HTML:
<div>
<h1 class='myLink'>Cocacola</h1>
<div>
<div>
<h1 class='myLink'>Sprite</h1>
</div>
</div>
</div>
The answers I've mentioned on top here suggest deleting the links so we can click the remaining elements with casper.exists and so on. What if I don't want to manipulate the page?
For reasons beyond my conception, using:
document.querySelector("div .myLink:nth-of-type(1)");
catches the first h1, Cocacola. But:
document.querySelector("div .myLink:nth-of-type(2)");
returns null.
Fiddle here.
Any ideas? Many thanks!
CSS spec for :nth-of-type says that:
The :nth-of-type(an+b) pseudo-class notation represents an element that has an+b-1 siblings with the same expanded element name before it in the document tree, for any zero or positive integer value of n, and has a parent element.
That is, the elements will have to be siblings.
For example,
<div>
<h1 class='myLink'>Cocacola</h1>
<h1 class='myLink'>Miranda</h1>
<div>
<div>
<h1 class='myLink'>Sprite</h1>
</div>
</div>
</div>
The selector div .myLink:nth-of-type(2) will select Miranda. That is, given n siblings of type 'div .myLink', the selector will select the second element from them.
Here is the fiddle for the above example.
Hope this helps!
As mentioned, the reason :nth-of-type(1) works but :nth-of-type(2) doesn't is because there is only exactly one h1 of each type as a child of its parent div. The class selector .myLink is a separate condition entirely and does not affect how :nth-of-type() works.
The reason your first statement appears to return the first element, even though there are technically two elements matching :nth-of-type(1), is because querySelector() returns only the first match.
To obtain the first and second elements matching your selector, use querySelectorAll() instead of querySelector(), and an indexer instead of the :nth-of-type() pseudo-class:
var cocacola = document.querySelectorAll("div .myLink")[0];
var sprite = document.querySelectorAll("div .myLink")[1];

jQuery: Select last match before specified element

Is there a way in jQuery to, given an element and a selector, select the last match of that selector before that element from an in-order traversal of the DOM tree?
For example, given the DOM tree:
<html>
<body>
<div class="a" id="div0" />
<div>
<div class="a" id="div1"/>
</div>
<div class="b" id="div2"/>
<div id="element"/>
<div class="a" id="div3"/>
<div class="b" id="div4"/>
</body>
</html>
Using the selector .a and element #element, you'd get #div1, and using the selector .b and the element #element, you'd get #div2.
The use case is writing a GreaseMonkey script to work across different versions of Firefox with some slightly mangled HTML. I've got an element I can find consistently in all versions, but another element I want to find is either a previous sibling of an ancestor of the element or a descendent of a previous sibling of an ancestor of the element (depending on the version).
All I can really rely on is that it is the last match of the selector that occurs before the element I have when doing an in-order traversal of the DOM tree.
This should do it, using your first example:
var $collection = $(".a, #element");
var eleIndex = $collection.index($("#element"));
var prevEl = $collection.eq(eleIndex - 1);
alert(prevEl.attr("id"));
http://jsfiddle.net/WdsGa/
Sortof. This will work for sibling elements just fine:
$("div.a:first").nextUntil("#element").last();
however, your nested div.a will not work with that snippet, I'm not sure of an efficient way to solve that. It selects the first element matched by div.a, then all siblings after it until it finds an element that matches #element, and then gets the last of those selected elements. But, again, it only works with siblings.
This should do it
var last = $(".a, #element").eq($(".a, #element").length-1);

how to find and apply style to grand parent div?

Is there a way I can find the grand parent of a div and apply style to it?
<div class="wrapBoxes">
<div class="filters"></div>
<div class="wrapContainer"> <-- Need to apply style to this -->
<div class="leftNav"></div>
<div id="container">
<div class="box"></div> <-- From here -->
</div>
</div>
</div>
Something with this logic?
$(".box").find(grandParent).applyWhateverCss to GrandParent
use parent twice:
$(".box").parent().parent().css('color', 'blue');
parent docs:
Description: Get the parent of each element in the current set of matched elements, optionally filtered by a selector.
You can use the closest as well.
$(".box").closest('.wrapContainer').css('color', 'blue');
closest docs:
Description: Get the first element that matches the selector, beginning at the current element and progressing up through the DOM tree.
If you are sure it will always be the grand parent, use parent().parent() otherwise use closest
as a performance u can also use .closest(selector[,context]) i.e
$('.box').closest('.wrapContainer','.wrapBoxes').css('color','yellow');
In this way u can limit the DOM traversal to the context of div.wrapBoxes only
$(".box").parent().parent().css('color','red'); should do it.
Alternatively if the class of "wrapContainer" is always there:
$(".box").parents('.wrapContainer').css('color','red');

Categories

Resources