I'd like to select a set of elements and their children from the DOM.
Then, I would like to run a set of selections on the DOM that excludes those elements, as if they were removed.
.not() seems to match both parent elements and child elements and doesn't properly exclude.
.find(':not(.myclass)') returns a list of about a bajillion elements and doesn't properly exclude.
What's my trouble? This seems simple but the functions I expect to do this don't behave as I expect.
I thought about cloning the DOM, removing the elements, and then running my selection matches on the cloned DOM... but that seems bad. Like, a major performance hit.
What's the best way to do this?
Here's the code I have:
jQuery('html').not(".page-node,.quote").find(selector).each(function(){
//do stuff here to returned elements
.page-node is a body class and should return the body element on nearly all pages and exclude the selector from being matched on those pages.
Edit: I have created a jsFiddle to demonstrate what I'm talking about: http://jsfiddle.net/glassdimly/H4tJe/4/
Not() will work with an appropriate descendant selector. A * following any selector will match all descendants (children, grandchildren etc). By applying it in a not, you can ask that all descendants be excluded from the match. As you also want to exclude the parent, include that in the not as well:
e.g.
$(selector).not(".page-node,.page-node *,.quote,.quote *")
Which equates to:
"Not has class page-node OR and child/descendant of page-node" or "Not has class quote OR any child/descendant of quote"
Updated JSFiddle: http://jsfiddle.net/TrueBlueAussie/H4tJe/7/
jQuery(document).find('.list').not('.exclude,.exclude *').each(function(){
this.remove();
});
Which equates to "Find all items has class list, but exclude any that also have class exclude and also exclude any descendants of any element that has class exclude"
Related
Hello this is my first question and I'm an amateur developer so forgive me in advance. I'm trying to grab this specific instance of the value class. The website I am working on has hundreds of different values associated with the value class.
<li class = "vin">
<strong class = "title">VIN:</strong>
<span class="value">121212121212121212</span>
</li>
Below is what I've been doing and it hasn't been working.
var vinNum = document.getElementsByClassName('li.vin','span.value');
console.log(vinNum.innerText);
Thank you
Although the existing answers cover the "modern" way to do this already - you can use most of the getElementsBy... (all, I think - was gonna say except getElementById, but that is named in singular for a reason, and because of the meaning of an id special) methods on all elements.
https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByClassName:
The Element.getElementsByClassName() method returns a live HTMLCollection containing all child elements which have all of the given class names. When called on the document object, the complete document is searched, including the root node.
So you can use that twice, to first select an element with one specific class, and then another with a different class "within it", among the descendants of the former. (Not "child elements", as the quoted MDN reference wrongly puts it.)
var vinNumContainer = document.getElementsByClassName('vin')[0],
vinNumElement = vinNumContainer.getElementsByClassName('value')[0];
(Necessary checks for whether elements exist before accessing them, what to do if more than one element (of either one) exists, etc., left out for brevity ;-)
But a simple call to querySelector is of course a quicker way to do it.
Try
var vinNum = document.querySelector('li.vin span.value');
console.log(vinNum.innerText);
This works because rather than selecting by class you're selecting the li.vin element which has a span.value as a child. vinNumber is now a node element. When you call vinNum.innerText you should get the correct number. When you console.log(vinNum) in uour example you will most likely see undefined or the incorrect element.
You can use the document.querySelector function in order to search elements on your page based on class, ID, or anything else that can be selected using a CSS selector.
Using Mozilla's CSS Selector reference, we can see that the CSS selector syntax to select an element which is a direct child of some other element is A > B, where A is a selector matching the parent, and B is a selector matching the child.
So one way to do this is to use:
var vinNum = document.querySelector('li.vin > span.value')
The one-liner above will match the first span element of class value which is a child of a li element of class vin.
However, if you have multiple examples of this structure (a li of class vin with a span of class value within it), using this selector won't work. In fact, if you want to have access to each specific span of class value individually, perhaps the best way would be to add a unique id attribute to each of them.
If your structure looked like this:
<li class = "vin">
<strong class = "title">VIN:</strong>
<span class="value" id="v25">121212121212121212</span>
</li>
You could then use the following:
var vinNum = document.querySelector('#v25')
One last alternative for when you have a list of nested HTML elements all with the same structure is to use document.querySelectorAll, which will return all DOM nodes which match your query and allow you to use JavaScript to run through them and select the values you want.
I have a line of jQuery code which I don't understand.
var layerid = $('ul.layerstack li.selected').data('layerid');
I understand that $(ul.layerstack) is to select ul elements with layerstack class, and similarly for li.selected. But I don't understand the syntax for juxtaposing the two with a space in between.
Can someone please help explain this syntax and give a reference for this? (The DOM structure is listed below for reference).
Thanks,
It is called as the descendant selector... it is a part of css selector spec.
It is used to select all elements which satisfies the second selector which are inside the first part
Descendant selectors
A space means "any descendant of": direct children and children of those children would be selected.
Actual case is much more complicated but please play along. I am trying to select siblings of element that has class 'sss', by using
$('.sss').parent().parent().find(">div.childCollapsible>div[data-onthemovecollapsible=true]")
I can only use CSS selectors (this is part of Selenium thest). I expected to get only siblings of 'sss' however I am getting all the children of sub elements too.
How could I restrict it only to siblings?
or any other workaround that can get me from any element in the tree siblings only of any
data-onthemovecollapsible="true"
attribute holder.
EDIT: Firstly I would like apologise for failing to express myself clearly. The structure that I am working with is 'infinite tree structure' that has unknown amount of nodes on each layer, mechanism I am looking for is ability to get siblings on the same level that I am starting search from is and only children of his parent (his brothers + himself). All levels of tree have identical HTML syntax, so looking at them relatively from element one starts from, each layer is identical, hence the CSS selector should be identical too. I cannot use any other Jquery method but 'find', and only can use CSS selectors, as mechanism is part of selenium test so only By.CssSelector("...") can be used. I can traverse up the elements by using element.FindElements(By.XPath("..")) that gets me parent as I know how many levels up parent is, but from parent position I need to get all siblings without children (that have identical html syntax) in one go, so i would assume selector with only certain layer should do (like one in jsfiddle below), however it selects all the children nodes too - does not respect '>' for some reason. This would do nicely if I could use all JQuery functions.
$('.sss').parent().parent().children().children()
what I need is same result but with CSS selector.
http://jsfiddle.net/2a46U/
I think this will work for you:
.find("body>div>div>div>div.childCollapsible>div[data-onthemovecollapsible=true]")
If I'm understanding this correctly, you have two different restrictions here. One is that you only want siblings of an .sss element. The other is that the parent of the element is div.childCollapsible. I don't believe you will be able to do this with a single selector/find. You would need something like this:
// get the siblings of .sss with appropriate data attribute
var $els = $('.sss').siblings("div[data-onthemovecollapsible=true]");
// filter the collection to only those with appropriate parent
$els = $els.filter(function(){
return $(this).parent().is("div.childCollapsible");
});
http://jsfiddle.net/2a46U/4/
I've updated your jsfiddle with two options (check the console please):
Get all the siblings:
$('.sss').siblings();
Get specific siblings:
$('.sss').siblings("div.AppletBase")
If you need to set styles you can use the siblings selector in CSS3:
.sss ~ div.AppletBase {/* Your styles in here */}
Anything please leave a comment and I will review it again if is needed
I need a javascript function or a CSS Selector (or even a ProtoypeJS function) which gets me ALL elements (ie. descendants) under a particular element.
I understand there are CSS selectors such as : 'p, a, div', which would get me all the elements of those three types. However I need to get EVERYTHING without specifying type.
ie. I want something like
myElement.getElements('*')
You can use querySelectorAll
myElement.querySelectorAll('*')
Note: Supported in IE8+
Compatible with all versions of IE, not just IE8+...
myElement.getElementsByTagName("*")
* is treated as a special case for getElementsByTagName to return all descendants regardless of tag name. (This is different to querySelectorAll, where * is a genuine selector that matches all elements)
The method that will get you all child elements as an extended PrototypeJS array is childElements() http://api.prototypejs.org/dom/Element/prototype/childElements/
element.childElements()
For other situations you might want to narrow down the child elements that are returned you can use select()
element.select('div')
will return all the div children of element
It's easy enough to do this with CSS alone. The * (universal) selector targets all elements. If you want to target all children of a specific element, then you can simply do this:
element * {}
How do I know what traverses the DOM and what doesn't?
$('div p')
It seems like this returns all the div elements AND THEN does another scan for P elements on each dom element that was returned in the first div search.
$('div .foo')
The class ones don't seem to scan the dom. They only filter the previous list $('div') for elements that contain classes foo. If a child of $('div') has class foo it is not selected.
$('div, div')
Doesn't contain dupes. So it seems to be scanning only once with a list of lambdas that either compare or they don't. But this gets really really confusing when you have filters like :contains('x') which seem like they can recurse the dom on their very own.
So how do these selectors work? Does 'div .foo' traverse for only divs first and then do a filter for classes that contain foo, or does it somehow get turned into a computation that says when tag==Div && class==foo. What about when there's multiple selectors? They show up in the order they appeared on the page without dupes making me feel like it only scanned the dom once. Maybe it just sorts and removes dupes before returning?
jQuery optimises it's selectors based on what is quickest. If there is a native browser supported method for getting an element (getElementById etc) it will use it, otherwise it will filter based on the results of the natively supported methods.