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];
Related
<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>
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')
I run into this problem frequently and never know the best approach. Imagine I have a structure that includes several instances of the following html:
<div class="known">
<div class="another unknown">
<div class="unknown">
<h4>Something a something</H4>
</div>
</div>
</div>
For each div of class known, I want to change the inner html of that div only if it contains a div inside it with some particular tag, in this case <h4>.
What is the best way to achieve that. I know that I could do it by taking the inner html of class known and doing a regex match. But is there a more robust way based on tags?
Simple, just use a selector that spans over the div.known and restrict it's context to div h4. If the selector selects at lease one element then the div.class has children as you expect.
if( $('.known div h4').length > 0 ){
$('.known').html('Some html');
}
Yes! You can do this.
var head = Array.prototype.slice.call(document.querySelectorAll("h4 #known"));
for(var i = 0; i < head.length; i++)
{
while(head[i].className !== "known")
head[i] = head[i].parent();
}
Now head will be an array of all the DOM elements have the tag known and have h4's in them.
With jQuery, you can use .has() to narrow your selection and even chain other methods, as in:
$(".known").has("h4").css("background","red");
Check out this fiddle for example. Notice that clicking the button will change the color of any div.known only if that element contains an h4 tag as a descendant.
Documentation on jQuery's .has() -- https://api.jquery.com/has/
I am using jquery, and I want to get all elements of a specific type that are not descendants of a particular kind of node.
E.g. my DOM is like:
<div id='idthatiknow'>
<div>
<span>good1</span>
</div>
<div>
<span>good2</span>
</div>
<p>
<span>bad</span>
<div>
<span>bad</span>
</div>
</p>
<div>
I need a selector that will get me good1 and good2 but not bad. But, I need to start at the id that I know. So I'm thinking, something like #idthatiknow not(p) span, but that doesn't work. Keep in mind, my actual dom is a lot more complicated - this is only a simplified example.
So, is there any way to retrieve all elements that are a descendant of X but not a descendant of Y?
You could always just filter on parents
$('#idthatiknow span').filter(function() {
return $(this).closest('p').length === 0;
});
FIDDLE
Note that it doesn't work on the last one, as a DIV can't be inside a P, so it's moved by the browser.
Someone posted an answer, but then deleted it. I am reposting it, because it was correct, but out of respect for whatever reason they had for removing their answer I will not name them and will make this community wiki. If they want to post it back again I will mark it correct, otherwise I will mark this answer correct.
They posted:
#idthatiknow > div span { /* your styles here */}
/* all spans with a direct child of div from #idthatiknow */
#idthatiknow span:not(#idthatiknow > div span) { /* your styles here */}
/* all spans except the ones with a direct child of div from #idthatiknow */
The second one solves the problem for me - it allows selecting an arbitrary descendant of an arbitrary element, excluding descendants of another element.
I have a function here for centering an element within it's parent.
Check out the demo: http://jsfiddle.net/kE9xW/1/
right now it's only applying the centering to the first element, how do i make the function loop itself so it centers every #element on the page. the demo is self explanatory, thanks!
There are a few things you need to do.
As already suggested, id's must be unique, so change the id="..." to class="...". You will also need to change your css to be based on the class not the id (change #element' to '.element')
<div class="container">
<p> ... </p>
<div class="element">
</div>
</div>
Use each in your method to loop over all elements selected by the selector $('.element').
element.each(function(){
// work here in $(this) for the current element
});
You forgot to take the top of the parent div into account, which made all elements overlap each other. So your yPas becomes:
var yPos = $(this).parent().position().top +
parseInt($(this).parent().css('height'))/2 -
parseInt($(this).css('height'))/2 - yPosFromCenter;
Check the working fiddle: http://jsfiddle.net/H99DT/
First, the easiest but most important part: change your IDs to classes. IDs must be unique per page so jQuery's ID selector and JavaScript's document.getElementById() function are only going to give you the first matching element:
Each id value must be used only once within a document. If more than one element has been assigned the same ID, queries that use that ID will only select the first matched element in the DOM.
Change
<div id="container">
...
<div id="element">
to
<div class="container">
...
<div class="element">
and change
$('#element')
to
$('.element')
Next, the more difficult part: you are currently issuing one centerDiv() call to your elements with coordinates from center of 0, 0. That's going to take all your .elements and position them at the exact same spot.
If that's not what you intend, you're going to have to loop through them using .each() and decide the xPosFromCenter and yPosFromCenter in each iteration. It's not clear to me yet how your function works so you may have to explore on your own and see what you can come up with.
Scratch that, see Jamiec's working example for the solution.
Change Id to class in you divs, then make container's position relative with css, and I'll suggest make jQuery plugin from your function. See results http://jsfiddle.net/kE9xW/1/