I'm having problems with html DOM.
How do I get the value from this path:
html body div table tbody tr td table tbody tr td table tbody tr td table tbody tr td form table tbody tr td
I can only find stuff like getElementbyID/tag/name/class etc.
How do I get the absolute DOM 'path' of the td element (let's say the 3rd cell of the second row in that table)?
I've been looking everywhere but cannot find a simple answer without ID/Class etc involved.
You could use querySelector(), but it doesn't have great support...
var elem = document.querySelector('html body div table tbody tr td table tbody tr td table tbody tr td table tbody tr td form table tbody tr td');
Otherwise just use a library that allows you to use CSS selectors, such as jQuery.
var $elem = $('html body div table tbody tr td table tbody tr td table tbody tr td table tbody tr td form table tbody tr td');
By the way, selecting like this is horrible for performance. Absolutely terrible. Have a read up on CSS selectors to learn why.
First, consider whether you do really need full paths. Referring to IDs or classes is more robust as they have less moving parts.
If full paths are what you need, you may wish to use XPath, as it's specifically designed for finding elements by path.
Here's a simple cross browser XPath library - there are many others.
Looks like you may want something like this:
For the following sample HTML,
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="findit.js"></script>
</head>
<body>
<div id="header">
<h1>Welcome to my ASP.net site!</h1>
</div>
<div id="h440292">
<table>
<!-- tbody omitted, but some (all?) browsers add it -->
<tr>
<td>junk</td>
<td>junk</td>
<td>junk</td>
</tr>
<tr>
<td>junk</td>
<td>junk</td>
<td>pick me!</td>
</tr>
</table>
</div>
</body>
</html>
this jQuery code will find the cell that says "pick me!"
$(function () {
var $resultCell = $("body")
.children("div").eq(1)
.children("table")
// Note I have to add this even though
// I omitted the tbody in the HTML markup
.children("tbody")
.children("tr").eq(1)
.children("td").eq(2);
alert($resultCell.text());
});
If performance becomes a problem, you may need to resort to doing something similar using the native DOM methods.
I am playing with this idea. I want to be able to find any node on a page (using a headless browser). Trying to build an absolute node path I created a recursive function, works but I am finding it is not completely unique which is annoying. On here for example, each post is templated so selecting text in the third response will reveal the same node path up the HTML tag as the first post
const buildPath = (node) => {
console.log(node);
if(node.tagName !== "HTML") {
path.unshift(node.tagName.toLowerCase())
buildPath(node.parentNode)
}
};
const path = [];
builtPath(<start node>);
document.querySelector(path.join(" "))
but this is where I am stuck now. Some things don't have any specific classes or names or ids to add to that. I may need to capture the innertext or innerhtml and try to match that. Kinda annoying. I suppose you could load like D3 and inject an incremental ID as data but then the site can't change at all, which may be true for this method too but I would think less so.
Related
I'm getting values of td if it contains "searched string" using
var t1=$(this).find('tr:has(td:first-child:contains("Error"))');
alert($(this).find('tr:has(td:first-child:contains("Error"))').css === "red"));
if (t1.length) {
str =t1.text().trim();
str = /:(.+)/.exec(str)[1];
errorArray.push(str);
// alert(str);
}
It is working fine. Now I want to add one more condition. How will I check for font colour of that. If it is equal to red then to proceed.Kindly help. If that can't be done then help me in searching for "Error" now how will I check using criteria "Match whole word". Search only for that particular string if any td has. If any td contains "Errorrr" it shouldn't consider that.
Check it... think, this is what yo need
$('table tr td').on('click',function(){
alert($(this).css('background-color'));
})
table tr td{ border:solid 1px; padding:2px}
table tr td:nth-child(even){ background-color:#ff3}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td>first</td>
<td>second</td>
<td>third</td>
<td>fourth</td>
</tr>
</table>
Here it is without JQuery, using getComputedStyle(). With this function you can get the actual style that is, after all the cascades and overwriting is done, rendered on the page:
const td = document.querySelector("table tr td"); // you can use JQuery here, if that makes you happy, or whichever way to select the element from the DOM.
const colour = getComputedStyle(td).backgroundColor;
console.log(colour);
This way you can get any actual, rendered CSS attribute from any element. The only caveat is to replace the kebab-case with camelCase (background-color -> backgroundColor).
I don't know the terminology but hoping this explanation makes sense. I have a JavaScript code that I want to repeat 10 times, each time with an increasing number to target each td in a table (first td then the second then the third and so on)
The goal of this JavaScript is to match the TD width of the thead to the one in the tbody (this is because I have them separated via css with position:absolute).
Right now I managed to match the width of a single TD with this:
var cell4 = $('#divResults tbody > td:nth-child(4)');
$('#divResults thead > tr > td:nth-child(4)').css({ width: cell4.width()});
The easiest, but not practical, way to accomplish setting the remaining TDs is to duplicate the JS but replacing the numbers 9 more times.
I know there is a way to create a loop and target each TD without manual duplication of the code but can't seem to find an answer online.
I appreciate the help
Instead of selecting a specific element, select all elements and loop over them.
$('#divResults tbody > td').each(function( index ) {
// Do some repeating code
});
Link for more details
https://api.jquery.com/each/
In vanilla JS you would use a for loop to achieve this. Using jQuery you can just grab a collection of <td>s and loop over them using .each
// Get the first tr's collection of td elements
var bodyTds = $('#divResults tbody tr:first-child td');
// Loop over the head td's (should be th's really)
$('#divResults thead tr td').each(function(index) {
// Apply the width of the body td to the head td
$(this).css({ width: bodyTds.eq(index).width()});
});
I am trying to use after() to place more DOM data (a <table>) after a $('tr'); I am noticing that the width of the new element changes the width of the tr's first td element. What can I do to prevent that?
$('#table tr').click(function(){
$(this).after(table);
$('#data').slideDown("slow");
});
http://jsfiddle.net/HZLLb/1/
As the comments stated, you can't have a table element in that position, and you should not repeat id's. You CAN, however, have multiple tbody elements, as well as multiple elements with the same class, which is likely the solution you are going for:
var table = '<tbody class="data" style="display:none;"><tr><td>Test</td><td>Test</td> <td>Test</td></tr></tbody>';
$('#table').on('click', 'tr', function(){
$(this).closest('tbody').after(table);
$('.data').last().slideDown("slow");
});
http://jsfiddle.net/HZLLb/3/
I am customising Sage CRM, so I have no control over the HTML that is written and can't add IDs or class's to the table layouts the CRM spits out. I want to hide a higher (not top) level table based on a users selection of a select dropdown. I can only get a jQuery selector hooked onto the title row of a table within the table I want to hide.
The DOM goes something like:
//Lots of other table structures above this in the DOM....
<table> <---- this is the table I want to show or hide based on the users selection
<tbody>
<tr>
<td>
<table>
<tbody>
<tr>
<td class="PANEREPEAT"> <---- this is the node I can get selector to
Valuation information
////
So I do the below client side javascript:
var val_information_screen;
$('.PANEREPEAT').filter(function () {
//Find the valuation information screen
return $(this).text() == 'Valuation information';
}).each(function () { //iterate through all of these (there should only be one!)
val_information_screen = $(this);
});
var sel_ofee_type = $('#ofee_type');
if (sel_ofee_type.val() == '006') {
val_information_screen.closest('table').parents("table:first").show();
} else {
val_information_screen.closest('table').parents("table:first").hide();
}
It does work, it just is not particularly beautiful. The bit that I really detest is below. Is there a better way to traverse up the DOM using jQuery?
val_information_screen.closest('table').parents("table:first").show();
val_information_screen.closest('table').parents("table:first").hide();
If you are sure that it has fixed structure, then you can use this,
$(td-selector).parents("table").eq(1).hide();
In your case,
val_information_screen.parents("table").eq(1).hide();
If your DOM (specifically starting from table you want to hide till the td you have as selector) is pretty much fixed, then the below selector can be used.
$('#element').parents('table').eq(1)
i have a href link under my table and i want to be able to manipulate table rows by clicking on that link but i cant get them !
here is my html
<div>
<div> <a href="#remove" class="removelink" > remove </a> </div>
<table>
<tr> <td></td> </tr>
</table>
</div>
i want to do something like:
$('.removelink').click(function(){
$(this).parent().siblings('table tr:last').remove();
})
i can get to the table by
$(this).parent().siblings('table')
but i cant get rows by something like
$(this).parent().siblings('table tr')
You can use find to get to the tr from the table:
$('.removelink').click(function(){
$(this).parent().siblings('table').find('tr:last').remove();
});
Here's a working example. If your HTML structure is always exactly as you've shown, you could use next() instead of siblings('table') for slightly shorter code.
The problem with your current code is that siblings('table tr') will look for a sibling of the div which is a tr, and there are none!
.siblings(selector) will return all siblings of a certain element which match the selector.
.siblings('table tr') will only return something if the context element has tr elements as siblings but the div does not.
Just use .find:
$(this).parent().siblings('table').find('tr').last()
var $context = $(this).parent().siblings('table');
$("tr:last", $context);