JavaScript get Info from table cells on button click - javascript

Every table row has a button "Show" located in a cell. On click of that button, I need to extract The text, contained in other cells of that exact row.
Example HTML:
<tr>
<td>1</td>
<td>Info1</td>
<td><input class="btn" value="Show" onclick="showRowInfo();" type="button"></td>
</tr>
<tr>
<td>2</td>
<td>Info2</td>
<td><input class="btn" value="Show" onclick="showRowInfo();" type="button"></td>
</tr>
<tr>
<td>3</td>
<td>Info3</td>
<td><input class="btn" value="Show" onclick="showRowInfo();" type="button"></td>
</tr>
What I want is: when I press (for example) the button on the 3rd row, to extract the text in the other 2 cells ("3" and "Info3").
I am looking for the implementation of the showRowInfo() in JavaScript, or at least a way to get the cells from the selected row.

Instead of setting an onclick attribute on each and every one of these buttons, I'd use a single event listener. Seeing as you added a jQuery tag, this code should do the trick:
$('table').on('click', '.btn', function()
{//replace table selector with an id selector, if you are targetting a specific table
var row = $(this).closest('tr'),
cells = row.find('td'),
btnCell = $(this).parent();
//set to work, you have the cells, the entire row, and the cell containing the button.
});
fiddle
If you want to do the same in vanillaJS:
document.querySelector('table').addEventListener('click', function(e)
{//same applies here: querySelector('#tableID') would be preferable
var target = (e = e || window.event).target || e.srcElement;
if (target.tagName.toLowerCase() === 'input' && target.className.match(/\bbtn\b/))
{
var btnCell = target.parentNode,
row = (function(node)
{
while (node.tagName.toLowerCase() !== 'tr')
node = node.parentNode;
return node
}(btnCell)),
cells = row.cells;
//set to work, you have the button-containing cell, the row and all of the cells
}
}, false);
This technique is called event delegation, google it in case you're not familiar with the idea behind it.

You have to pass this in showRowInfo(this) ,
onclick="showRowInfo(this);"
function showRowInfo(elm) {
alert($(elm).closest("tr").find("td:lt(2)").text());
}
DEMO

Related

Using Conditional If statements with JavaScript DOM Table?

I have been given a table that has been created using the DOM and now I have to use if statements to print specific areas of that table. For example in the second photo, when i click 1 - 2 million, it should show the table but only display the countries that have a population that's between 1 and 2 million. My teacher has barely taught us JavaScript deeply and now gives us a DOM assignment that uses JavaScript If Statements. I would appreciate if someone could give an explanation on how i can print specific parts of the table when i click the links/button above. Thanks!
Here a roadmap:
Loop through your submenus with a for (or for ... in) statement and attach a click event listener on each one with addEventListener()
In the callback, this will refer to the <li> (or <a>, or whatever) element you clicked (and which is linked to an event). So you can access the DOM clicked element's data nor attributes.
In function of the clicked submenu, filter your <table> the way you want thanks to if statements. (even better: switch statement) Visually, rows will be hidden. In Javascript, you will update style attribute of the element.
Below an example. I propose to you to try to do it yourself with elements I gave you. Open the snippet if you are really lost.
Exemple:
Other functions/methods/statements I used below: querySelectorAll(), dataset, instanceof, parseInt(), onload, children
// Always interact with the DOM when it is fully loaded.
window.onload = () => {
// Gets all <button> with a "data-filter-case" attribute.
const buttons = document.querySelectorAll('button[data-filter-case]');
// For each <button>, attach a click event listener.
for (let i in buttons) {
const button = buttons[i];
// The last item of "buttons" is its length (number), so we have to check if
// it is a HTMLElement object.
if (button instanceof HTMLElement) {
button.addEventListener('click', filterTable); // Will execute the "filterTable" function on click.
}
}
}
// The function which will filter the table.
function filterTable(e) {
// Useless in my exemple, but if you have <a> instead of <button>,
// it will not execute its original behavior.
e.preventDefault();
// Get the value of "data-filter-case" attribute.
const filterCase = this.dataset.filterCase;
// Get all table body rows.
const tableRows = document.querySelectorAll('table > tbody > tr');
// Update display style of each row in function of the case.
for (let i in tableRows) {
const row = tableRows[i];
if (row instanceof HTMLElement) {
if (filterCase === 'more-than-44') {
if (parseInt(row.children[1].innerText) <= 44) {
// Hide the row.
row.style.display = 'none';
} else {
// Reset display style value.
row.style.display = '';
}
} else if (filterCase === 'less-than-27') {
if (parseInt(row.children[1].innerText) >= 27) {
row.style.display = 'none';
} else {
row.style.display = '';
}
} else if (filterCase === 'reset') {
row.style.display = '';
}
}
}
}
<button type="button" data-filter-case="more-than-44">More than 44</button>
<button type="button" data-filter-case="less-than-27">Less than 27</button>
<button type="button" data-filter-case="reset">Show all</button>
<table>
<thead>
<tr>
<th>ID</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<th>1</th>
<td>45</td>
</tr>
<tr>
<th>2</th>
<td>50</td>
</tr>
<tr>
<th>3</th>
<td>24</td>
</tr>
</tbody>
</table>

Showing Hidden Row in Table

I am using some code based on the following JSFiddle. The intention is to show more information when the user clicks the "Show Extra" link.
The problem that I'm having is that when the link is clicked on all but the bottom row of the table the hidden element is shown briefly and then closes.
I am populating my table using template strings in javascript. Here is the code that I use to add rows to the table:
this.addRecordToTable = function(bet, index, id){
console.log(index);
console.log($.data(bet));
var butId = id.toString();
if (bet.bookies == null){
bet.bookies = "";
}
if (bet.bet == null){
bet.bet = "";
}
var newRow = `
<tr>
<td>${bet.date}</td>
<td>${bet.bookies}</td>
<td>${bet.profit}</td>
<td><button id=${butId}>Delete</button></td>
<td>Show Extra</td>
</tr>
<tr>
<td colspan=\"5\">
<div id=\"extra_${index}\" style=\"display: none;\">
<br>hidden row
<br>hidden row
<br>hidden row
</div>
</td>
</tr>
`
console.log(newRow);
console.log("#"+butId);
$(newRow).appendTo($("#betTable"));
$("#"+butId).click(
function()
{
if (window.confirm("Are you sure you want to delete this record?"))
{
var rec = new Records();
rec.removeRecordAt(index);
$("#betTable tbody").remove();
var c = new Controller();
c.init();
}
});
$("a[id^=show_]").click(function(event) {
$("#extra_" + $(this).attr('id').substr(5)).slideToggle("slow");
event.preventDefault();
});
}
EDIT:
I had to change $("a[id^=show_]").click to $("a[id=show_"+index).click..., as the event handler was being added to each element every time I added a new element. Thanks to #freedomn-m.
This code:
$("a[id^=show_]")
adds a new event handler to every existing link as well as the new one as it's not ID/context specific so all the show a's match the selector.
You need to add the context (newRow) or use the existing variable(s) as part of the loop that are already defined, eg:
$("a[id^=show_]", newRow)
$("a#show_" + index)
(or any other variation that works).
An alternative would be to use even delegation for the dynamically added elements, eg:
$(document).on("click", "a[id^=show_]", function...
in which case you'd only need to define/call the event once and it would be fired for new elements (ie put that outside the new row loop).

Changing td to textbox when clicked and changing textbox back to td when user is done

I'm looking for a way the user can change a td from table by clicking on it. My current setup is when a user clicks on a td, it should replace the clicked td by a textbox which contains the text from the clicked td. Then when the user clicks outside of it, or presses enter. It should change the textbox back to td.
This is the Table I have:
<table class="table" id="tableCompleted">
<thead>
<tr>
<th>Name</th>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
</tr>
</thead>
<tbody>
<tr>
<td>John</td>
<td>Yes</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>Jesse</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>David</td>
<td>No</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
</tr>
</tbody>
</table>
This is the script I have written, the problem I have is that, when a users clicks on a td it replaces all the td's and I havent figured out how to change it back when it loses focus. I tried using a button but that made it even worse. Also the text from the td doesn't get placed inside the textbox.
The script I used for it:
$('td').click(function () {
$('td').replaceWith(function () {
return '<input type="text" id="modify" "value="' + $('#Text').val() + '" />';
});
})
I Currently have 3 problems with it, Im not sure how to only change the td that is clicked, because all the td don't have a unique id or class. And I'm not sure how to change it back when the user is done changing it. Also It doesn't place the content of the td inside the textbox.
For referring to the clicked element you can use the this keyword:
$('td').on('click', function() {
$(this)...
});
Also you shouldn't replace the td with an input, because a trelement can't have an input child. Instead of it remove the textContent of the td and append an input to it. Here is one way of implementing this:
$('td').on('click', function() {
var $this = $(this);
var $input = $('<input>', {
value: $this.text(),
type: 'text',
blur: function() {
$this.text(this.value);
},
keyup: function(e) {
if (e.which === 13) $input.blur();
}
}).appendTo( $this.empty() ).focus();
});
Here is a demo using the above snippet.
You have also a more sensible option: contentEditable property.
$('td').prop('contentEditable', true);
Using the above property browser handles the editing. You can either manually add a contentEditable to the target cells in your markup or use JavaScript for modifying the attribute.
Pure javascript solution here. And additionaly jsfiddle demo
Fight the crime :)
(function(){
'use-strict';
var td = document.getElementsByTagName('td');
for(var i=0;i<td.length;i++) {
td[i].addEventListener('click', change, false);
}
function change() {
if(this.firstChild.nodeType !== 3) {
return;
}
var docFrag = document.createDocumentFragment();
var input = document.createElement('input');
input.value = this.textContent;
this.removeChild(this.firstChild);
docFrag.appendChild(input);
this.appendChild(docFrag);
}
}());
You can use this. Here is a working demo.
$('td').click(function () {
$(this).replaceWith(function () {
return '<input type="text" id="modify" value="' + $(this).text() + '"> </input>';
});
})
To get it back you can use attach focusout on this.

Highlight table rows on hover containing same info with JS or jQ

My boss told me to build a table with rows that highlight and if -for example- the text or number is the same as the text or number on another row's column-two, that will also highlight.
I know I can give each row a class value and make any object with the same class highlight but my boss requires it to highlight depending on the text or number of a certain column.
This is my jsFIDDLE example.
If you look at column-two of each row, you'll see that the value for row-one and three are the same, so if I was to hover over row-three, it should along with row-one highlight and vise versa.
<table>
<tr>
<td>01/12/13</td>
<td>1234567</td>
<td>Lorem</td>
</tr>
<tr>
<td>02/12/13</td>
<td>7654321</td>
<td>Ipsum</td>
</tr>
<tr>
<td>02/01/14</td>
<td>1234567</td>
<td>Dolor</td>
</tr>
</table>
How can I write a script which allows this to happen without using classes?
// Mouse over event handler
$('table').on('mouseover', 'td', function() {
// Store the hovered cell's text in a variable
var textToMatch = $(this).text();
// Loop through every `td` element
$('td').each(function() {
// Pull selected `td` element's text
var text = $(this).text();
// Compare this with initial text and add matching class if it matches
if (textToMatch === text)
$(this).parent().addClass('matching');
});
});
// Mouse out event handler
// This simply removes the matching styling
$('table').on('mouseout', 'td', function() {
$('.matching').removeClass('matching');
});
JSFiddle demo.
Note that I've modified your CSS slightly to add:
tr:hover, tr.hover, tr.matching {
background: #E5E5E5;
}
Fiddle : http://jsfiddle.net/JLubs/4/
JS :
$(document).ready(function(){
$('table tr td:nth-child(2)').each(function(){
$index = $(this).parent().index() ;
var atext = $(this).html();
$('table tr td:nth-child(2):contains('+atext+')').not(this).parent().attr('match', $index );
});
$('[match]').on('mouseover', function(){
$matchInde = $(this).attr('match');
//alert($matchInde);
$('table tr:eq('+parseInt($matchInde)+')').addClass('highlight');
}).on('mouseout', function(){
$matchInde = $(this).attr('match');
$('table tr:eq('+parseInt($matchInde)+')').removeClass('highlight');
});
});

Filter td elements in a tr out, that are not displayed

I have a Datatable in asp.net that i want to modifiy. I select the <tr> rows of the Datatable with JQuery:
var rows = $("#dgInformation tr:gt(0)");
However, the <tr>elements have multiple <td>elements and some of them are marked as display:none. How can i get the rows-variable without those hidden cells?
The purpose of this is to check cells if they are different from each other and only one line for each difference should be displayed. If i dont filter the not displayed elements, they get also compared and i have lines, which are visually the same.
Update
It works with just adding a CSS class to the <td>-elements that should be hidden. Then you have a clean DOM-Tree (i hope i can call it this way) in Firebug. The whole function below for reference:
function filterTable()
{
var rows = $("#dgInformation tr:gt(0)");
var prevRow = null;
var counter = 2;
rows.each(function (index) {
if (prevRow !== null) {
var i = 1;
var changes = 0;
$(this).children("td:visible").each(function () {
if(i > 2){
if ($(':nth-child(' + i + ')', $(prevRow)).html() != $(this).html())
{
$(':nth-child(' + i + ')', $(prevRow)).css('backgroundColor', '#00FF00');
changes = changes + 1;
}
}
i++;
});
if(changes == 0)
{
$(prevRow).css('display','none');
$(prevRow).removeClass();
}
else
{
$(prevRow).removeClass();
if(counter % 2 == 0)
$(prevRow).addClass('dgItemStyle');
else
$(prevRow).addClass('dgAlternatingItemStyle');
counter = counter + 1;
}
}
prevRow = this;
});
}
You can use the :not() filter for this.
If you have html like
<table id='tableid'>
<tr><td></td>
<td class="hidden">Hidden Cell</td>
<td>3</td>
<td>4</td></tr>
<tr>
<td>5</td>
<td class="hidden">Hidden Cell</td>
<td>6</td>
<td>7</td>
</tr>
<tr>
<td>8</td>
<td class="hidden">Hidden Cell</td>
<td>9</td>
<td>1</td>
</tr>
</table>
CSS:
.hidden{
display:none;
}
Script:
If u want all the td elements in that table without hidden td elements then,
var rows = $("#dgInformation tr:gt(0) td:not('.hidden')");
It would work!!
Try this:
var rows = $("#dgInformation tr:gt(0)").find('td').not(':visible').remove();
I see you're using jQuery.. So would
var rows = $("#dgInformation tr:gt(0)").not($("#dgInformation tr:gt(0)").has("td[display=none]"));
work?
Since you only want the td's that are visible, the following should suffice:
var visible_cells = $("#dgInformation tr:gt(0)").find("td:visible");
If you want the ones that are not visible, use :hidden instead :)
Update
I'm not sure what you mean by "How can i get the rows-variable without those hidden cells?".
If I read that correctly, you basically want the row, and have it's non-visible cells removed from the variable but kept in HTML.
This can't be done, as the variable you hold is still based on the actual HTML. The row-variable will not even contain any of the children. They will be looked up in the DOM when you request them specifically.
However, I assume at some later stage in your code, you actually get the selected row's <td> children. Apply the :visible filter on them whenever you need them, or make a second variable which holds the children you want, like I suggested in my answer.
You just can't pre-emptively delete them from a variable without altering the HTML.

Categories