I have a simple table like this
<table id="tempTable">
<tbody>
<tr id="row_01">
<td>
<button onclick="btnclick(this);" >Save Row</button>
</td>
</tr>
<tr id="row_02">
<td>
<button onclick="btnclick(this);" >Save Row</button>
</td>
</tr>
</tbody>
</table>
function btnclick(e) {
var currentRow = $(e).parent().parent();
alert(currentRow.id);
}
I want to determine which row where the button clicked was placed. So I use some jquery method in btnclick() as you see abow. But sometime I don't know how deep level the button was placed in row (), so Im looking for a way to get an ancestor by tag <tr> of a element.
Anybody help me, thanks?
Try this :
function btnclick(e) {
var currentRow = $(e).closest('tr');
alert(currentRow.id);
}
The closest() function will return the closest ancestor referenced by its selector. In this case the selector is simple a <tr> element.
Taken from the jQuery docs :
.closest( selector )
Get the first element that matches the selector, beginning at the current element and progressing up through the DOM tree.
A better method could be used if you change your HTML a little bit. If you placed the same class on each of your buttons.
Eg :
<td>
<button class="myBtnClass" >Save Row</button>
</td>
Then your jQuery would look like this :
$(".myBtnClass").on('click',function(){
var currentRow = $(this).closest('tr');
alert(currentRow.attr('id'));
});
This function will capture a click on any element with the .myBtnClass class.
The jQuery way is:
$('#tempTable').find('button').click(function() {
var currentRow = $(this).closest('tr');
});
how about using closest
function btnclick(e) {
var currentRow = $(e).closest('tr');
alert(currentRow.id);
}
Related
I need to change all ID after cloning node below by javascript or jquery.
<table id="1">
<tr>
<td id="RM_1"><button type="button" onclick="duplicateFunction(1)"></td>
<td id="CL_1"><input id="[1][999]"/></td>
</tr>
</table>
when I clone node with ID = "1" I need to change 1 to 2 as in all ID tags below.
<table id="2">
<tr>
<td id="RM_2"><button type="button" onclick="duplicateFunction(2)"></td>
<td id="CL_2"><input id="[2][999]"/></td>
</tr>
</table>
Remark : The table id is unique id. I use simple number to explain the code.
update
When user click duplicate button. The duplicateFunction will be called.
now , I can change table id but I can't change inside.
function duplicateFunction(table_id){
var myTable = document.getElementById(table_id);
myClone = myTable.cloneNode(true);
var newTableID = Date.now();
myClone.id = newTableID;
document.getElementById("AddingSpace").appendChild(myClone);
}
because every tags have another features to do when user click.
that's the best way on this time.
Thank you in advance
This is an attempt along the lines suggested by Rory McCrossan. Instead of the individual ids of your elements inside the table I used shortened class names. The tables do not have actual ids but dataset attributes with id properties. This way it will not cause serious problems if ids should become double ...
My function calculates a newid on the basis of the number of already existing tables in the #addingspace div. This is not production ready either but probably less problematic than your original approach.
const $trg=$('#addingspace');
$(document).on('click','.RM button',function(){
let newid=$trg.find('table').length+2;
$trg.append(
$(this).closest('table').clone().data('id',newid) // set data-id
.find('.CL span').text(newid).end() // set span and return cloned element
)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table data-id="1">
<tr>
<td class="RM"><button type="button">duplicate</button></td>
<td class="CL"><input /> id: <span>1</span></td>
</tr>
</table>
<div id="addingspace"></div>
I will have this button once for each table (about 25 distinct tables) on this page and I'm hoping to find a way to have the onclick event call the function constructDataValueString and pass in the id of the parent table (so that I don't have to explicitly reference the table id).
Is there a way to write:
onclick="constructDataValueString(*id_of_parent_table*)"
Graphical example of the HTML markup:
You can use closest(), for example:
onclick="constructDataValueString(this.closest('table').id)"
Example
const constructDataValueString = (id) => console.log("table id is: ", id);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:50% !important;}
<table id="populationbyage" border="2">
<thead>TABLE</thead>
<tbody>
<tr>
<td>
Some Cell...
</td>
<td>
<button onclick="constructDataValueString(this.closest('table').id)">
Copy
</button>
</td>
</tr>
</tbody>
</table>
Sure - use this.parentNode.parentNode.parentNode.parentNode.id:
function constructDataValueString(id) {
console.log(id);
}
<table id="populationbyage">
<tbody>
<tr>
<td>
<button onclick="constructDataValueString(this.parentNode.parentNode.parentNode.parentNode.id)">Copy</button>
</td>
</tr>
</tbody>
</table>
(The above is a minimalistic example - it follows the exact same structure, it just has only the necessary elements and attributes required.
To ensure your internal table structure can change without affecting this part, you could use this.closest("table") so that you get the first parent <table> element, from where you can get the id:
constructDataValueString(this.closest("table").id)
A more flexible solution
function parent(el, selector) {
var matchesFn;
// find vendor prefix
['matches', 'webkitMatchesSelector', 'mozMatchesSelector', 'msMatchesSelector', 'oMatchesSelector'].some(function (fn) {
if (typeof document.body[fn] == 'function') {
matchesFn = fn;
return true;
}
return false;
});
var parent;
// traverse parents
while (el) {
parent = el.parentElement;
if (parent && parent[matchesFn](selector)) {
return parent;
}
el = parent;
}
return null;
}
<table id="populationbyage">
<tbody>
<tr>
<td>
<button onclick="console.log(parent(event.target, '#populationbyage'))">Copy</button>
</td>
</tr>
</tbody>
</table>
As other answers suggest, use closest()
https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
To answer your question and also to address someone who wants a particular element to be sent, there is a way to exactly send the id of the table or any tag which you want.
`<table id="populationbyage" border="2">
<thead>TABLE</thead>
<tbody>
<tr>
<td>
Some Cell...
</td>
<td>
<button onclick="constructs(this.closest('#populationbyage').id)">
Copy
</button>
</td>
</tr>
</tbody>
</table>
<script>
function constructs(id) {
console.log(id)
}
</script>
`
The fetching of the id approach will pinpoint to the table you want to access here. It will help you to ignore all the nested tables if in future you wish to add some.
Suppose onclick handler is set for a <tr> is it possible to disable/overwrite it for one particular <td>?
<tr onclick='somefunction()'>
<td> </td> <!--onclick should work here-->
...
<td> </td> <!--onclick should not work here-->
...
<td> </td> <!--onclick should work here-->
</tr>
Of course I can set it for each <td> separately or pass the name of a td to the function and decide what to do based on this name, but it seems like there should be a simpler solution.
I found the easiest was to stop the event being passed to the parent html using onclick=event.stopPropagation() in the <td> tag.
So <td class=whatever onclick=event.stopPropagation()>cell data<td>
In somefunction you could check the cellIndex of the td, and return early, if a non-clickable cell has been clicked. Something like this:
function somefunction (e) {
if (e.target.cellIndex === 1) {return;}
/* Do something, the td is clickable */
}
To get this work with an inline handler, you've to pass the event object:
<tr onclick='somefunction(event)'>
A live demo at jsFiddle.
Things will get a bit more complex, if you've elements within cells. In that case you have to find a td parent element, like so:
function somefunction (e) {
var target = e.target; // Cache the target element
while (target) { // Iterate through elements
if (target.tagName === 'TD') { // TD found, stop iteration
break;
}
target = target.parentElement; // Set target as a parent element of the current element
}
if (target === null) {return;} // Check that we really have a TD
if (target.cellIndex === 1) {return;} // A non-clickable cell clicked
:
}
A live demo at jsFiddle.
Edit 2018
In 2018 elements have closest() method, hence the loop above is not needed, target = e.target.closest('td') will make sure a td is used.
A very simple way would be to use CSS pointer-events: none, but unfortunately this doesn't work in FF in this particular case in IE<11 at all, though works well in Chrome and IE11. Also preventing pointer events would be bad, if the cell happens to contain interactive elements.
A live demo at jsFiddle.
EDIT:-
Try something like this.
HTML:
<tr id="row">
<td> </td> <!--onclick should work here-->
...
<td class="noChange"> </td> <!--onclick should not work here-->
...
<td> </td> <!--onclick should work here-->
</tr>
JavaScript:
window.onload = function() {
var row = document.getElementById("row");
for (i=0; i<row.childNodes.length; i++) {
if (row.childNodes[i].class != "noChange") {
row.childNodes[i].onclick="doStuff()";
}
}
}
<html>
<body>
<table border="1">
<tr onclick='somefunction(this)'>
<td><input type="text"></td> <!--onclick should work here--> ...
<td><input type="text"></td> <!--onclick should not work here--> ...
<td><input type="text"></td> <!--onclick should work here-->
</tr>
</table>
<script>
function somefunction(element) {
var td = element.children;
console.log(td);
var inputObj = td[1].children;
console.log(inputObj[0]);
inputObj[0].disabled = true;
}
</script>
</body>
</html>
The children property 'element.children' returns a list of an element's child elements, as an HTMLCollection object.
enjoy :)
I have a case where a html file contains multiple elements with the same ID name.
The table row contains 5 columns of which I need to consider 2,3,4,5 columns data.
<tr id='total_row'>
<td>Total</td>
<td>%(count)s</td>
<td>%(Pass)s</td>
<td>%(fail)s</td>
<td>%(error)s</td>
<td> </td>
</tr>
I have the above code at several places in the file. I need to add the respective values using javascript.
An ID is unique in an html page. You can call it THE ID as well wrt a page. You cannot have same ID for two different tags in a single page. But you can use class instead of and ID. Know about it here
So your HTML can be like
<tr class='total_row'>
<td>Total</td>
<td>%(count)s</td>
<td>%(Pass)s</td>
<td>%(fail)s</td>
<td>%(error)s</td>
<td> </td>
</tr>
As an example with jquery you can do something like this,
<!DOCTYPE html>
<html>
<head>
<style>
</style>
</head>
<body>
<table>
<tr class="one">
<td></td>
<td></td>
</tr>
<tr class="one">
<td></td>
<td></td>
</tr>
<tr class="one">
<td></td>
<td></td>
</tr>
</table>
<script src="jquery-1.11.0.min.js"></script>
<script>
$(document).ready(function() {
$(".one").eq(0).find('td').eq(0).html("I'm tracked");
// get 1st tr and get first td
$(".one").eq(1).find('td').eq(1).html("I'm tracked");
// get 2nd tr and get second td
$(".one").eq(2).find('td').eq(0).html("I'm tracked");
// get 3rd tr and get first td
});
</script>
</body>
</html>
But I guess this approach can be tedious.
Id should be unique and if you use the same id, javascript code refers only the first element. but if you still want to use same id than you may try the below code:
$(function(){
$('[id="total_row"]').each(function(){//run for every element having 'total_row' id
var $this = $(this);
$this.find('td').eq(1).text() //to get second column data
$this.find('td').eq(1).text('dummy text') //to set second column data
});
});
You can use XHTML:
<p id="foo" xml:id="bar">
Through XHTML you can apply similar ID to multiple Controls.
Similar questions can be found here:
http://www.c-sharpcorner.com/Forums/
While duplicate IDs are invalid, they are tolerated and can be worked around. They are really only an issue when using document.getElementById.
I'll guess that the table looks like:
<table id="t0">
<tr>
<td>-<th>count<th>Pass<td>Fail<td>Error<td>
<tr>
<td>-<td>1<td>1<td>0<td>0<td>
<tr>
<td>-<td>1<td>1<td>0<td>0<td>
<tr id='total_row'>
<td>Total<td><td><td><td><td>
<tr>
<td>-<td>1<td>1<td>0<td>0<td>
<tr>
<td>-<td>1<td><td>1<td>0<td>
<tr>
<td>-<td>1<td><td>0<td>1<td>
<tr id='total_row'>
<td>Total<td><td><td><td><td>
</table>
<button onclick="calcTotals();">Calc totals</button>
If that's correct, then a function to add each sub–section can be like:
function calcTotals(){
var table = document.getElementById('t0');
var rows = table.rows;
var row, totals = [0,0,0,0];
// For every row in the table (skipping the header row)
for (var i=1, iLen=rows.length; i<iLen; i++) {
row = rows[i];
// If it's a total row, write the totals and
// reset the totals array
if (row.id == 'total_row') {
for (var j=0, jLen=totals.length; j<jLen; j++) {
row.cells[j+1].innerHTML = totals[j];
totals[j] = 0;
}
// Otherwise, add values to the totals
} else {
for (var k=0, kLen=totals.length; k<kLen; k++) {
totals[k] += parseInt(row.cells[k + 1].innerHTML) || 0;
}
}
}
}
In addition to using classes, which works but feels kind of icky to me, one can also use data-* attributes.
<tr class='total_row' data-val-row-type="totals-row">
<td>Total</td>
<td>%(count)s</td>
<td>%(Pass)s</td>
<td>%(fail)s</td>
<td>%(error)s</td>
<td> </td>
</tr>
Then, in your script (jQuery syntax -- querySelectorAll has a similar syntax)
var $totalsRows = $("[data-val-row-type='totals-row']);
When you are in a team with a separate UI designer, this keeps the UI guy from ripping out and changing your class names to fix the new design layout and it makes it quite clear that you are using this value to identify the row, not just style it.
Please tell me two methods below to catch the <table> (line 3) which has no specific attribute like "id" or "class name" and input the first 3 rows <tr>something1</tr> <tr>something2</tr> <tr>something3</tr> with javascript.
Method 1: from the Top to the Bottom tag: div -> div -> table (subclass 3)
Method 2: from the Bottom to the Top tag: <table id="Hero-WPQ1"> up to <table> (line 3).
<div id="content_data">
<div>
<table>
<tbody>
<tr>
<td>
<table>
<tbody>
<tr>something1</tr>
<tr>something2</tr>
<tr>something3</tr>
<tr>something4</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<table class="ms-bottompaging">
something
</table>
<table id="Hero-WPQ1">
something
</table>
</div>
You can use .eq():
var firstTable = $('#content_data table').eq(0);
or :eq() selector:
var firstTable = $('#content_data table:eq(0)');
or .first():
var firstTable = $('#content_data table').first();
Basically, there are many ways to help you to get the first table as long as it's the first table inside #content_data in your case
For method 2, you can use .siblings() along with :first selector:
var firstTable = $('#Hero-WPQ1').siblings(':first');
You can use .prev() method like:
$('#Hero-WPQ1").prev().prev()
which gives you first table want you to desired.
for <tr>something1</tr> you can:
$('#Hero-WPQ1').prev().prev().find('tr:first')