How do i get all children (ie children of children) with Javascript? - javascript

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 * {}

Related

Grabbing a class within a class with javascript

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.

Understanding element types

Let's say I have multiple buttons that use a class named submit. I add this reference to jQuery.
When the button is clicked; it should be disabled.
Scripts I could use:
A.$('.submit').click(function () { this.disabled = true; });
B.$('#submit').click(function () { this.prop('disabled'), true); });
C.$('#submit').click(function () { $(this).disabled = true; });
D.$('.submit').click(function () { $(this).prop("disabled", true); });
The correct answer is D.
So, personally, I was pretty sure it was C. (which is wrong) because I saw the # before submit. I do this alot with questions like these, where I try to assume I know what the correct selector is. Which I always assume # is the correct one.
In hindsight the question states it's a class so I believe that's where the . is appropriate. However, without being told it's a class, I would have just guessed.
Sometimes I see an id referenced like so #imnotaclass or what have you, which is confusing me.
Can someone better explain jquery selectors to me, when to use # , ., or
In jQuery there's documentation on the selectors. Is there not continuity between other languages ie, css, html. I noticed with those 2 I can pass in something and use # on all fronts. However it will be an id and yet it still works.
The reason I bring this up is to better understand; on an exam what the correct answer is.
If "submit" is a class name, then the correct answer would be A:
$('.submit').click(function () { this.disabled = true; });
because it is the only answer that selects an element with that class name and properly sets the disabled property inside the event handler.
The code inside the event handler is wrong for options B, C and D so there is no way that they could be considered correct.
The question seems to be checking your knowledge of three things: 1) CSS selector syntax, 2) how to set properties on a DOM element and 3) what is the value of this in a jQuery event handler and how you use it.
The two correct ways to set the disabled property inside the event handler are:
// use direct DOM property access
this.disabled = true;
// use jQuery's .prop()
$(this).prop("disabled", true);
As for CSS selector syntax basics:
A selector that starts with # targets an ID value identified with id="xxx" in the HTML or set as a property on the DOM element.
So "#submit" references a single element with an id as in
<button id="submit">Press Here</button>
A selector that starts with . targets a class name identified with class="xxx" in the HTML or set as a property on the DOM element.
So ".submit" references one or more objects with a given class name as in
<button class="submit">Press Here</button>
ID values must be unique in the document (only be used on one single element). Class names can be used on as many elements as desired.
If you want to see more about the selectors that jQuery uses, you can read this tutorial.
If you were going to use jQuery inside the event handler, it would be this:
$('.submit').click(function () {
$(this).prop('disabled', true);
});
As shown in the jQuery documentation for .prop().
If "submit" was an id value, then the correct answer would be:
$('#submit').click(function () {
$(this).prop('disabled', true);
});
Inside your jQuery event handler, the value of this will the DOM element that you registered for the event on. That means if you use something like this.id, then you must be referencing DOM properties or calling DOM methods.
If you want to call jQuery methods, then you would use $(this) to turn it into a jQuery object so you can then use jQuery methods or properties.
Keep in mind that every jQuery object contains an array of zero or more DOM elements. You can access the individual DOM elements in the jQuery object via the array syntax as in $(this)[0] or via the .eq() method as in $(this).eq(0) and a jQuery object has a .length property which tells you how many DOM elements are in the array as in $(this).length === 1.
This is excerpted from the documentation. I'm posting this here as supporting information for #jfriend00's answer
Sizzle is the selector engine which jQuery uses.
Note: In supported browsers, jQuery will attempt to use document.querySelectorAll() to resolve CSS selector queries rather than it's internal selector engine if the requested selector does not use jQuery extensions that are not supported by document.querySelectorAll(). This is done for performance reasons
Selectors
CSS3
Sizzle supports virtually all CSS 3 Selectors, including escaped selectors (.foo\+bar), Unicode selectors, and results returned in document order. The only exceptions are those that would require additional DOM event listeners to keep track of the state of elements.
As such, the following pseudo-selectors are not supported:
:hover
:active
:visited, :link
Note: These CSS3 pseudo-selectors were unsupported prior to version 1.9:
:target
:root
:nth-last-child
:nth-of-type, :nth-last-of-type, :first-of-type, :last-of-type, :only-of-type
:lang()
Other selectors and conventions
Changes
Full selector lists in :not(); e.g. :not(a.b), :not(div > p), :not(div, p)
Nested pseudo-selectors; e.g. :not(:has(div:first-child))
Additions
[NAME!=VALUE]: Elements whose NAME attribute doesn't match the specified value. Equivalent to :not([NAME=VALUE]).
:contains(TEXT): Elements with textContent containing the word 'TEXT'. Case-sensitive.
:header: Header elements (h1, h2, h3, h4, h5, h6).
:parent: Elements with at least one child node (either text or an element).
:selected: (option) elements that are currently selected
Form Selector Additions
Note: In this context, input, button, select, and textarea are all considered to be input elements.
:input: Input elements
:button: Input elements that are buttons or have type "button"
:checkbox, :file, :image, :password, :radio, :reset, :submit, :text: Input elements with the specified type
Positional Selector Additions
In this context, "positional" refers to an element's placement in the collection after a selection, based on document order. For example, div:first would return an array containing the first div on the page, while div:first em would target the first div on the page and select all em elements within.
Note: Positional indexes begin at zero.
:first/:last: The first/last matching element
:even/:odd: Even/odd-numbered elements
:eq/:nth: The nth element; e.g. :eq(5) finds the 6th element
:lt/:gt: Elements at positions above/below the specified position
https://github.com/jquery/sizzle/wiki#selectors

Exclude matched DOM & children from selection?

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"

Multiple Level Element Selection using Core JavaScript

How it could be possible in JavaScript. Select any X element on the base of some other selector
Like. I can do it using jQuery Some thing like that
x = $('#key').children('.left').children('input');
// In this example I am using id Selection, Class Selector and Element Selector
I tried to do this using JavaScript in this way
x = document.getElementById('key')
.getElementByClassName('left')
.getElementByName('input');
But i was unsuccessfully. I also search in on over the internet but there is no usefully solution for this. But How jQuery works in this Scenario for All Browser
Using querySelectorAll:
document.querySelectorAll('#key > .left > input')
This is equivalent to jQuery version $('#key').children('.left').children('input');.
Support: IE8+.
Also note that you can also make use of getElementsByClassName (IE9+) and getElementsByName but it would be not so convenient if you really want to select direct children elements > and not all children. In this case I would go with for loops and children properties checking classes and tag names.
If you are okay with any depth elements and not only direct children I would recommend to go with getElementsByTagName.

Some questions about how jquery selectors traverse the dom

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.

Categories

Resources