js vanilla on click delegate on tr of a table - javascript

I'm trying to find on click a data attribute from the tr element of a table with the delegated click event, but it doesn't return anything, what am I wrong?
I made a fiddle to try and test
document.querySelector('table#listaCar tbody').addEventListener('click', e => {
if (e.target.matches(".car-item")) {
alert(e.target.getAttribute('data-id-car'));
}
});
table#listaCar tbody tr {
cursor: pointer;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<table id="listaCar" class="table table-bordered table-hover bg-white">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Status</th>
<th scope="col">Date</th>
<th scope="col">N. IUV</th>
</tr>
</thead>
<tbody>
<tr data-id-car="4140" class="car-item">
<td>4140</td><td>TO PAY</td><td>13-05-2022</td><td>10</td>
</tr>
<tr data-id-car="4129" class="car-item">
<td>4129</td><td>TO PAY</td><td>12-05-2022</td><td>15</td>
</tr>
</tbody>
</table>

e.target is the td, not the tr.
Easiest solution is to use .parentNode to get the td's parent: the tr then you can test using matches and get the data attribute as desired
const tr = e.target.parentNode;
if (tr.matches(".car-item")) {
alert(tr.getAttribute('data-id-car'));
}
document.querySelector('table#listaCar tbody').addEventListener('click', e => {
const tr = e.target.parentNode;
if (tr.matches(".car-item")) {
alert(tr.getAttribute('data-id-car'));
}
});
table#listaCar tbody tr {
cursor: pointer;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<table id="listaCar" class="table table-bordered table-hover bg-white">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Status</th>
<th scope="col">Date</th>
<th scope="col">N. IUV</th>
</tr>
</thead>
<tbody>
<tr data-id-car="4140" class="car-item">
<td>4140</td><td>TO PAY</td><td>13-05-2022</td><td>10</td>
</tr>
<tr data-id-car="4129" class="car-item">
<td>4129</td><td>TO PAY</td><td>12-05-2022</td><td>15</td>
</tr>
</tbody>
</table>

You need to do a test on the element click to see if it is a table cell (TD) and if it is grab the parent.
In my example I am looping through all the rows to apply the click.
document.querySelectorAll('.car-item').forEach(item => {
item.addEventListener('click', e => {
let el = e.target.tagName === "TD" ? e.target.parentElement : e.target;
alert(el.getAttribute('data-id-car'));
});
});
table#listaCar tbody tr {
cursor: pointer;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<table id="listaCar" class="table table-bordered table-hover bg-white">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Status</th>
<th scope="col">Date</th>
<th scope="col">N. IUV</th>
</tr>
</thead>
<tbody>
<tr data-id-car="4140" class="car-item">
<td>4140</td><td>TO PAY</td><td>13-05-2022</td><td>10</td>
</tr>
<tr data-id-car="4129" class="car-item">
<td>4129</td><td>TO PAY</td><td>12-05-2022</td><td>15</td>
</tr>
</tbody>
</table>

Related

How to populate a table td

I've created a table and I need to populate the tds using JavaScript because the data is coming from the server.
Here is my table:
<table id="report" class="infoRecurso" id='testExportId' style="width: 100%; color: #363636">
<thead style="color: #363636">
<tr class='btn-danger' style="background-color: lightgray; color: #363636">
<th class="thData">Data</th>
<th id="timeIniticial" class="thInicio">Início</th>
<th class="thTermino">Término</th>
<th class="thDuracao">Duração</th>
<th class="thAtividades">Atividades</th>
</tr>
</thead>
<tbody id="myTable">
<tr>
<td style="text-align: left;"></td>>
<td id="inicialTime"></td>
<td>Hora Final</td>
<td style="text-align: left;">Duração</td>
<td colspan="1" class="quebraLinha" style="text-align: left;"></td>
</tr>
<tr>
<th class="horasTotaisTh" colspan="3"> Horas Totais </th>
<th class="resultadoHorasTotaisTh" colspan="4">Hora Total</th>
</tr>
</tbody>
I am trying to populate the td with the id inicialTime that is corresponding to the tr timeIniticial. I've tried using this code:
var data = [{"product": "RD0"}, {"product": "RD1-184"}, {"product": "RD1-185"}];
var table = $('.infoRecurso');
$.each(data, function(i, value) {
table.find('tr').eq(i).find("td[id='inicialTime']").text(value.product);
});
but this code only populates the first position.
How can I populate the rest of tds positions?
Your question leaves a few points open, so I can only guess what you really want. In the following snippet I have compiled a solution that will .prepend() some html code to your table, to the effect that your second column is always filled with the code from your data array. I changed the id attribute of this <td> element to class since IDs must always be unique.
I also "corrected" your colspan attributes of the last table row since there are only 5 columns in total.
var data = [{"product": "RD0"}, {"product": "RD1-184"}, {"product": "RD1-185"}];
var html=data.map(({product})=>
`<tr><td></td><td class="inicialTime">${product}</td><td>Hora Final</td>
<td>Duração</td><td class="quebraLinha"></td></tr>`).join('')
$('.infoRecurso tbody').prepend(html);
td {text-align:left}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="report" class="infoRecurso" id='testExportId' style="width: 100%; color: #363636">
<thead style="color: #363636">
<tr class='btn-danger' style="background-color: lightgray; color: #363636">
<th class="thData">Data</th>
<th class="thInicio">Início</th>
<th class="thTermino">Término</th>
<th class="thDuracao">Duração</th>
<th class="thAtividades">Atividades</th>
</tr>
</thead>
<tbody id="myTable">
<tr>
<th class="horasTotaisTh" colspan="3"> Horas Totais </th>
<th class="resultadoHorasTotaisTh" colspan="2">Hora Total</th>
</tr>
</tbody>

Bootstrap: data-sort on dynamic table

I have a bootstrap table as follows:
<table id="fullDataTable"
class="table table-bordered"
data-toggle="table"
data-classes="table"
data-striped="true"
data-sort-name="numFrame"
data-sort-order="desc">
<thead>
<tr>
<th class="col-sm-1"
data-field="numFrame"
data-sortable="true">numFrame</th>
<th class="col-sm-1"
data-field="timeStamp"
data-sortable="false">timeStamp</th>
<th class="col-sm-1"
data-field="id_robot"
data-sortable="false">idRobot</th>
</tr>
</thead>
<tbody id="dataTable">
</tbody>
</table>
The table is then filled dynamically with values from a MySQL database with Javascript:
socket.on('gotDataQuality', function(message) {
if(message == 0){
alert('No Quality datas for this session');
clearElement("dataTable");
}else{
clearElement("dataTable");
for (var i = message.length-1; i >= 0; i--) {
$('#dataTable').prepend('<tr><td>'+message[i].numFrame+'</td><td>'+message[i].timeStamp+ '</td><td>'+message[i].idRobot+'</td></tr>');
}
}
});
The table fills correctly but when I attempt to sort it (by clicking on one of the sortable headers) the contents of the table is erased. I'm not entirely sure how the data-sort element works, what can I do to resolve this?
You can use List JS
You can make use of this example
var options = {
valueNames: [ 'id', 'firstname', 'lastname','username' ]
};
var userList = new List('table', options);
.table [data-sort] {
cursor: pointer;
}
.table [data-sort]::after {
margin-left: .25rem;
content: url('data:image/svg+xml;utf8,<svg width=\'6\' height=\'10\' viewBox=\'0 0 6 10\' fill=\'none\' xmlns=\'http://www.w3.org/2000/svg\'><path fill-rule=\'evenodd\' clip-rule=\'evenodd\' d=\'M3 0L6 4H0L3 0ZM3 10L0 6H6L3 10Z\' fill=\'%238898aa\'/></svg>');
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
<div id="table">
<table class="table">
<thead>
<tr>
<th scope="col" class="sort" data-sort="id">#</th>
<th scope="col" class="sort" data-sort="firstname">First Name</th>
<th scope="col" class="sort" data-sort="lastname">Last Name</th>
<th scope="col" class="sort" data-sort="username">Username</th>
</tr>
</thead>
<tbody class="list">
<tr>
<th scope="row" class="id">1</th>
<td class="firstname">Mark</td>
<td class="lastname">Otto</td>
<td class="username">#mdo</td>
</tr>
<tr>
<th scope="row" class="id">2</th>
<td class="firstname">Jacob</td>
<td class="lastname">Thornton</td>
<td class="username">#fat</td>
</tr>
<tr>
<th scope="row" class="id">3</th>
<td class="firstname">Larry</td>
<td class="lastname">the Bird</td>
<td class="username">#twitter</td>
</tr>
</tbody>
</table>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js"></script>
CodePen

jQuery click event is not working on table

I'm having a table in my react application. I'm trying to implement click event like this:
$('#detailedTable tbody').on('click', 'tr', function() {
//var row = $(this).parent()
if ($(this).next('tr').hasClass('row-details')) {
$(this).next().toggle();
return;
}
})
I placed this inside componentDidMount method.
This is my table:
<table className="table table-hover table-condensed table-detailed"
id="detailedTable" ref={node => this.table_el = node}>
<thead>
<tr>
<th className="sorting_disabled wd-5p"></th>
<th >Title</th>
<th className="wd-15p">Channel</th>
<th className="wd-10p">File Type</th>
<th className="wd-15p">Uploaded</th>
<th className="wd-20p">Process</th>
<th className="wd-10p">Status</th>
</tr>
</thead>
{ this.state.MediaFiles.map((item, i) => (
<tbody>
<tr onClick={this.rowClick} id={i}>
<td className="v-align-middle">
<div className="checkbox">
<input type="checkbox" value="3" id={"checkbox1" + i}/>
<label htmlFor={"
But the click event is not getting fired. What is wrong?
Click event works perfectly with the following HTML:
$('#detailedTable tbody').on('click', 'tr', function() {
console.log('click works!');
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table className="table table-hover table-condensed table-detailed" id="detailedTable" ref={node => this.table_el = node}>
<thead>
<tr>
<th className="sorting_disabled wd-5p">
</th>
<th>Title</th>
<th className="wd-15p">Channel</th>
<th className="wd-10p">File Type</th>
<th className="wd-15p">Uploaded</th>
<th className="wd-20p">Process</th>
<th className="wd-10p">Status</th>
</tr>
</thead>
<tbody>
<tr onClick={this.rowClick} id={i}>
<td className="v-align-middle">
TBODY ITEM (click it)
</td>
</tr>
</tbody>
</table>
$(document).on('click', '#detailedTable tbody tr', function() {
//var row = $(this).parent()
if ($(this).next('tr').hasClass('row-details')) {
$(this).next('tr').toggle();
return;
}
});

Javascript to target a table that comes after an H1 containing specific text

I would like to target a table only if it comes after an H1 containing 'Editing Shared Regions'
Here is the html showing the table I want to target:
<h1>Editing Shared Regions</h1>
<ul class="smartbar">
<li class="selected">Regions</li>
</ul>
<table>
<thead>
<tr>
<th>Region</th>
<th>Type</th>
<th>Items</th>
<th class="action"></th>
<th class="action"></th>
</tr>
</thead>
<tbody>
You can use :contains(), general sibling selector ~
$("h1:contains('Editing Shared Regions') ~ table")
.css("color", "blue")
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>Editing Shared Regions</h1>
<ul class="smartbar">
<li class="selected">Regions
</li>
</ul>
<table>
<thead>
<tr>
<th>Region</th>
<th>Type</th>
<th>Items</th>
<th class="action"></th>
<th class="action"></th>
</tr>
</thead>
<tbody>
</table>
Here's an example that doesn't use jQuery. I shouldn't extend the DOM but it makes it fun to write a one-liner like guest271314's example.
NodeList.prototype.contains = function(searchText) {
for (var ix = 0; ix < this.length; ix++) {
if (this.item(ix).innerText.trim() === searchText) {
return this.item(ix);
}
}
return null;
}
Node.prototype.findNext = function(tag) {
var el = this;
while (el.nextSibling) {
el = el.nextSibling;
if (el.tagName && el.tagName.toUpperCase() === tag.toUpperCase()) {
return el;
}
}
return null;
}
document.querySelectorAll('h1').contains('Editing Shared Regions').findNext('table').style.color = 'red';
<link href="//cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" rel="stylesheet"/>
<div class="container">
<h1>A Heading</h1>
<table>
<tr>
<td>This is not the table you're looking for</td>
</tr>
</table>
<h1>Editing Shared Regions</h1>
<ul class="smartbar">
<li class="selected">Regions</li>
</ul>
<table>
<thead>
<tr>
<th>Region</th>
<th>Type</th>
<th>Items</th>
<th class="action"></th>
<th class="action"></th>
</tr>
</thead>
<tbody>
<tr>
<td>PNW</td>
<td>Land</td>
<td>meow</td>
<td>x</td>
<td>y</td>
</tr>
</tbody>
</table>
</div>

Automatically get info for ::before element with JavaScript

I've been trying to figure out a wait to get this to work with having multiple tables on a single web page.
<table class="table table-striped basic">
<thead>
<tr>
<th>Saturday</th>
<th class="time">10:30am</th>
<th class="time">11:00am</th>
<th class="time">11:30am</th>
<th class="time">12:00pm</th>
</tr>
</thead>
<tbody>
<tr>
<td>3/5/2016</td>
<td>15231</td>
<td>15232</td>
<td>15233</td>
<td>15234</td>
</tr>
<tr>
<td>3/5/2016</td>
<td>15231</td>
<td>15232</td>
<td>15233</td>
<td>15234</td>
</tr>
<script>
var time = $('.time').text();
$(function() {
$('table td:nth-child(2)').attr('data-before-content', time);
$('table td:nth-child(3)').attr('data-before-content', time);
$('table td:nth-child(4)').attr('data-before-content', time);
$('table td:nth-child(5)').attr('data-before-content', time);
});
</script>
CSS:
.table td:nth-child(2)::before {
content: attr(data-before-content);
}
Trying to figure out a way to get the context of each "th" and place it ::before in the CSS while having multiple tables. Any suggestions?
Are you thinking something along the lines of this? You can use a combination of .each(), .eq(), and .not()
$('table tr').each(function(){
$('td', this).not(':first-child').each(function(i){
$(this).attr('data-before-content', $('.time').eq(i).text());
});
});
.table td:before {
content: attr(data-before-content) '\00a0';
}
.table td {
padding: 1em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="table table-striped basic">
<thead>
<tr>
<th>Saturday</th>
<th class="time">10:30am</th>
<th class="time">11:00am</th>
<th class="time">11:30am</th>
<th class="time">12:00pm</th>
</tr>
</thead>
<tbody>
<tr>
<td>3/5/2016</td>
<td>15231</td>
<td>15232</td>
<td>15233</td>
<td>15234</td>
</tr>
<tr>
<td>3/5/2016</td>
<td>15231</td>
<td>15232</td>
<td>15233</td>
<td>15234</td>
</tr>
</tbody>
</table>
In case the .time data is table specific (which is more likely the case I would think), I'd recommend using this instead:
$('table tr').each(function(){
var $t = $(this).closest('table').find('.time');
$('td', this).not(':first-child').each(function(i){
$(this).attr('data-before-content', $t.eq(i).text());
});
});
.table td:before {
content: attr(data-before-content) '\00a0';
}
.table td {
padding: 1em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="table table-striped basic">
<thead>
<tr>
<th>Saturday</th>
<th class="time">10:30am</th>
<th class="time">11:00am</th>
<th class="time">11:30am</th>
<th class="time">12:00pm</th>
</tr>
</thead>
<tbody>
<tr>
<td>3/5/2016</td>
<td>15231</td>
<td>15232</td>
<td>15233</td>
<td>15234</td>
</tr>
<tr>
<td>3/5/2016</td>
<td>15231</td>
<td>15232</td>
<td>15233</td>
<td>15234</td>
</tr>
</tbody>
</table>
<table class="table table-striped basic">
<thead>
<tr>
<th>Monday</th>
<th class="time">7:30pm</th>
<th class="time">9:00pm</th>
<th class="time">10:30pm</th>
</tr>
</thead>
<tbody>
<tr>
<td>3/7/2016</td>
<td>15231</td>
<td>15232</td>
<td>15233</td>
</tr>
<tr>
<td>3/7/2016</td>
<td>15231</td>
<td>15232</td>
<td>15233</td>
</tr>
</tbody>
</table>
var time = $('.time'); returns an all the text of all element with the class .time. Instead, you should use something like $('.time:nth-child('+i+')').text() inside a for-loop.
<script>
var time = $('.time');
$(function() {
for(var i = 0, len=time.length; i<len; i++){
$('table td:nth-child(' +i+ ')').attr('data-before-content', $(time[i]).text());
}
});
</script>

Categories