Selecting a DOM element that doesn't have any selectors whatsoever - javascript

I desire to select a DOM element that doesn't have any selectors whatsoever (and it's not my site so I can't add these myself).
Let's assume I cannot target it by textContent or offsetWidth because many other HTML objects (elements) in the webpage has the same textContent and/or offsetWidth, so it's not a good method in this case, by principle.
My question:
I would assume each DOM element has a "machine-identifier" of some sort, that I could utilize to select the object with document.querySelector.
It might be selected by a unique number (index) in an array (if we look at the DOM tree as an array).
Is there indeed any machine identifier or index I could utilize to select the element with document.querySelector?
I tried to search for such but basically I didn't find any. Maybe the terminology I used was wrong.
I don't look for a jQuery or CSS solution, but rather only vanilla JS.

Right-click your element in Chrome, and select inspect.
Then, in the inspector, in the HTML code, right-click it again and choose copy selector (or copy Xpath).
For instance, if I want to select the words "My question:" from your question, it gives me :
#question > table > tbody > tr:nth-child(1) > td.postcell > div > div.post-text > h2
This is the unique absolute CSS selector for 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.

CSS selector .find(">div.childCollapsible>div[data-onthemovecollapsible=true]") is not respecting parent restriction

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

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.

What CSS rule do I need to hide "tr" elements whose children "td"'s have child "input" elements with empty value attributes?

I realize the question title is a bit confusing, but in reality, I mean to ask exactly what I've typed.
I am trying to write a CSS file for printing (nausea rising) and I am wanting to eliminate white space in unnecessary rows (the necessity, or rather, the lack thereof, is determined by input fields that have empty values).
The proper CSS syntax (if there exists any) is relentlessly eluding me.
I have used selectors like this before:
input[type=text]
So I could assume (hopefully... gulp!) that I could use something like:
input[val='']
However:
1) I'm not sure using apostrophes/quotes is even legal inside those brackets (what's that area of a CSS selector called, again?)
2) I wouldn't know how to put a selector inside those brackets (if even possible) since the actual "tr"s are what I'm trying to target, just "tr"s with td children with input children with empty vals.
Wallowing in random syntax, I tried:
tr[td input val=]
Very much NOT to my surprise, did I find that obviously this didn't work, then I realized I had no clue how to proceed, if I wanted to accomplish this strictly in CSS.
~ Takes a quick breathe
Okay, I realize I'm asking a lot out of CSS, but if it's selector system wasn't so powerful I wouldn't even assume this possible.
Lastly, I am already implementing javascript, jQuery, and even server-side C#.net (WebMatrix) so if this answer is best solved using these other languages, I don't mind, I just want the simplest cleanest solution, if possible, as any scripting method I use will require the addition of another class to all td elements therein, and there are many, not to mention the scripting itself.
Any help, as always, is greatly appreciated.
---------------------EDIT REGARDING ALNITAK'S ANSWER------------------------
I tried to add the following jQuery just before my window.print(); JavaScript command:
$('tr > td > input[value=""]').parent().parent().css('display', 'none');
$('tr > td > input[value=""]').parent().parent().css('visibility', 'hidden');
I have checked my # of parents, and all is as it should be there. The only other thing that might be interfering is that I have razor embedded in the values by default (although they are explicitly assigned empty strings on page start so, it should be fine). Just in case though I also tried:
$('tr > td > input[value=null]').parent().parent().css('display', 'none');
$('tr > td > input[value=null]').parent().parent().css('visibility', 'hidden');
But, alas, to no avail.
You can't do this with pure selectors, because the end result of a selector is always the matching child node, not their ancestors.
You need to find those matching child nodes, and then climb back up the tree again, e.g. in jQuery:
$('tr > td > input[value=""]').parent().parent().css('color', 'red');
You can use .closest('tr') instead of .parent().parent() if you prefer.
Also using jQuery, you can use the .has() function to create a chain that matches elements containing particular children:
$('tr').has('> td > input[value=""]').css('color', 'red');
The .has() function is more efficient than using the :has pseudo-selector, although I would expect neither to be as efficient as the full selector above which takes advantage of document.querySelectorAll on modern browsers.
If you can't get the input[value=""] part to work, try this:
$('tr > td > input').filter(function() {
return this.value == '';
})....
If I'm understanding you correctly :
You can't do what you want to in CSS, not yet anyway.
What you're looking for is a css parent selector.
http://css-tricks.com/parent-selectors-in-css/
By using the selector:
tr td input[value='']
You'll be selecting the inputs, not the <tr>s.
One way to achieve what you want is to have something "watch" the page you're on (from javascript) and apply a class to anything you want hidden, when you print. Then in your print stylesheet just use that class to hide!
Your prose translates to this CSS:
!tr>td>input:matches(:not([value]),[value=''])
However, both ! and :matches are CSS4 selectors that are not implemented yet. You'd be better off using JavaScript:
var qsa = document.querySelectorAll("tr>td>input"), l=qsa.length, i;
for( i=0; i<l; i++) {
if( qsa[i].value == '') qsa[i].parentNode.parentNode.style.display = "none";
}
Try using the :has() selector: http://api.jquery.com/has-selector/
Description: Selects elements which contain at least one element that matches the specified selector.
$('tr:has(td input[value=""])').css({color:'red'});

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