I want to make a row in a table selectable, however whenever I click the row, the console log shows that it did the right thing, but didn't change its class. Why is that and how can I fix it?
Part of the Code, that generates the select feature:
var tableconn = document.getElementById("connectionsLane"+laneid);
let row = tableconn.insertRow();
row.id = "row"+insertData.id;
row.onclick = function() {
if (row.classList.contains("selected")) {
console.log("unselected");
row.classList.remove("selected");
} else {
console.log("selected")
document.getElementById("row" + insertData.id).classList.add("selected");
}
}
insertData.id gets increased by 1 each time the whole thing is called, whilst laneid is dependent on which part of the website the user is currently refering to (is a int 1-255)
Here is a simple example of how you can select a table row and style it using a function. This function can be used for setting class name on rows in any table in a document.
// for setting the class name on a row in a table
const onrowselect = e => {
let table = e.target.closest('table');
let trs = table.querySelectorAll('tr');
// remove all class=selected
trs.forEach(tr => tr.classList.remove('selected'));
// the current tr
var tr = e.target.closest('tr');
tr.classList.add('selected');
};
// define a table
var table01 = document.getElementById('table01');
// add and eventlistener to the table
table01.addEventListener('click', onrowselect);
tr {
cursor: pointer;
}
.selected {
background-color: silver;
}
<table id="table01">
<tr>
<td>Row</td>
<td>1</td>
</tr>
<tr>
<td>Row</td>
<td>2</td>
</tr>
<tr>
<td>Row</td>
<td>3</td>
</tr>
</table>
Related
I have a table generated with data from an array (the array contains more info than what is displayed in the table). I want to click on a row to see all info from the element.
Earlier done it like this:
let rows = document.getElementsByTagName("tr");
for (let row of rows) {
row.onclick = function rowClicked(evt) {
selected = myArray[evt.target.parentElement.rowIndex];
//code (not relevant)
}
But since I added a search feature myArray[1] is not necessarily equal to row number 1 and this method doesn't work.
Is it another way to find the element in the array from clicking on a random row?
The table is generated like this:
function drawTable(data) {
let table = document.getElementById("table");
table.innerHTML = "";
let tableHead = document.createElement("thead");
let colHeads = ["Names"];
for (let header of colHeads) {
let cell = document.createElement("th")
cell.innerHTML = header;
tableHead.appendChild(cell);
}
table.appendChild(tableHead)
for (var i = 0; i < data.length; i++){
let row = document.createElement("tr");
let name = document.createElement("td");
name.innerHTML = data[i].name.first + " " + data[i].name.last;
row.appendChild(name);
table.appendChild(row);
}
}
Any help is greatly appreciated!
You need some way to map a table row to its relevant entry in myArray which isn't dependent on the position of the row in the table. Data attributes wouldn't be affected.
Create a data-index attribute on each table row. Then, when it's clicked use the value of the data-index attribute to access the relevant myArray entry.
A simple version of what you have in mind. The visible line is bound with a click event. As soon as it is triggered, it gets the ref-id from the clicked element and toggles the reference column.
const clickables = document.querySelectorAll('.clickable');
console.log(clickables)
clickables.forEach(tr => {
tr.addEventListener('click', (e) => {
const ref = e.target.parentElement.getAttribute('data-ref');
const row = document.querySelector('#' + ref);
row.classList.toggle('hide');
});
});
td {
text-align: center;
padding: 20px;
}
.hide {
display: none;
}
.clickable {
cursor: pointer;
}
.clickable:hover {
background: #ccc;
}
<table border="1">
<tr class="clickable" data-ref="a">
<td>1</td>
<td>2</td>
</tr>
<tr id="a" class="hide">
<td>a1</td>
<td>b2</td>
</tr>
<tr class="clickable" data-ref="b">
<td>3</td>
<td>4</td>
</tr>
<tr id="b" class="hide">
<td>a3</td>
<td>a4</td>
</tr>
</table>
I Created a HTML Table and Created 1 Row in it... I created two functions first to Clone and the Row and second to Remove the Row..
using appendchild and removechild function
But removeChild Function Deletes the Main Row as well...
I want the removeChild Function to be only able to remove cloned Rows, Not the original row...
Note: in Clone of Row, I have replaced the ID with " ". to remove duplicate id.
i Tried to do this by creating a if statement which check if the id of row is same as original row only then remove the row. but I think I am not doing it in right way.. Below is code..
<table id="table-logic">
<tbody id="qualiBody">
<tr>
<td>column 1</td>
<td>column 2</td>
<td>column 3</td>
<td>column 4</td>
</tr>
</tbody>
</table>
<a onclick="cloneRow()">Add Row</a><br>
<a onclick="removeRow()">Remove Row</a>
//clone Row with changed id
function cloneRow() {
var row = document.getElementById('addr00'); // find row to copy
var table = document.getElementById("qualiBody"); // find table body to append to
var clone = row.cloneNode(true); // copy children too
clone.id = ' '; // change id to a blank space
table.appendChild(clone) // add new row to end of table
}
//Remove Row
function removeRow() {
var table = document.getElementById("qualiBody"); // find table to append to
var mainRow = document.getElementById("qualiBody")
if (mainRow.childNodes.id != 'addr00') {
table.removeChild(qualiBody.lastChild);
}
}
I expect to make my removeRow Function only remove cloned Rows... Not the Original Row...
I think the if statement can work in that part by Just making javascript check the id of element... if id of row != id of original row .. remove last child.
//clone Row with changed id
function cloneRow() {
var row = document.getElementById('addr00'); // find row to copy
var table = document.getElementById("qualiBody"); // find table body to append to
var clone = row.cloneNode(true); // copy children too
clone.classList.add("cloned");
table.appendChild(clone) // add new row to end of table
}
//Remove Row
function removeRow()
{
var table = document.getElementById("qualiBody");
let last = table.lastElementChild;
if (last.classList.contains("cloned"))
{
last.remove();
}
}
<table id="table-logic">
<tbody id="qualiBody">
<tr id="addr00"><td>column 1</td><td>column 2</td><td>column 3</td><td>column 4</td></tr>
<tr class="cloned"><td>column 1</td><td>column 2</td><td>column 3</td><td>column 4</td></tr>
<tr class="cloned"><td>column 1</td><td>column 2</td><td>column 3</td><td>column 4</td></tr>
<tr class="cloned"><td>column 1</td><td>column 2</td><td>column 3</td><td>column 4</td></tr>
</tbody>
</table>
<a onclick="cloneRow()">Add Row</a><br>
<a onclick="removeRow()">Remove Row</a>
What I'm trying to do here, is, for every row in the table, I want to verify the row's data attribute (Note that the data attribute of this row is the socket One of the keys in the clientel dictionary previously made) with the keys in the dictionary clientel. If both match, do nothing. If the key is in the row but not in the dictionary, perform a function and if there's a key in the dictionary but it's not in a row, then add that row.
let clientel = {
socket101: ['Rick', '192.590.49.1', 'Win10', 'Norway', '15:49.00'],
socket102: ['Anthony', '192.90.897.0', 'Win7', 'Negritine', '19:19:38']
};
function man_table() {
const table = document.getElementById('table-body');
for(let i in clientel) {
for(let ih = 0, row; row = table.rows[ih]; ih++) {
ass = row.getAttribute('data');
if (ass in clientel) {}
else if (!(ass in clientel)) {table.deleteRow(ih); continue;}
else if (clientel[i] !== ass) {
let row = table.insertRow(i);
let client = clientel[i];
row.setAttribute('data', i);
let name = row.insertCell(0);
let ip = row.insertCell(1);
let os = row.insertCell(2);
let country = row.insertCell(3);
let timee = row.insertCell(4);
name.innerHTML = client[0];
ip.innerHTML = client[1];
os.innerHTML = client[2];
country.innerHTML = client[3];
timee.innerHTML = client[4];
}
}
}
}
Why doesn't this add the tables and
Is there a better way to do this?
Example of the HTML table (On Request):
<div id="table">
<table>
<thead>
<tr>
<th>Name</th>
<th>IP</th>
<th>OS</th>
<th>Country</th>
<th>Connected Since</th>
</tr>
</thead>
<tbody id="table-body">
<tr>
<td>Rick</td>
<td>192.423.41.5</td>
<td>Win 7</td>
<td>Bulgaria</td>
<td>A few moments</td>
</tr>
</tbody>
</table>
</div>
Don't try and do too many things at the same time. Adding rows in the same loop where you're deleting rows is going to cause confusion.
Notice that your HTML does not actually have the data attributes on the TR elements, so your code will never match any rows. Also, trying to this: let row = table.insertRow(i); will fail because i is a string ("socket101" etc)
The delete first looks for rows that don't have a corresponding entry in the clientel dictionary. [...table.rows] converts the HTMLCollection into an array so that filter can be used, which simply returns the entry from the dictionary matching it's data attribute. This will be null for any row that doesn't have an entry.
Once we have a list of rows that don't have matching clients remove the rows. Find the index of the row by deconstructing the row ( .forEach({rowIndex}) => foo(rowIndex) has the same effect as .forEach(row) => foo(row.rowIndex) ), and then delete the row (remembering to account for the table header row).
Adding the new row is about the same as the delete. The .map( (key, index) ) => [ key, index ] ) is used to preserve the index of each client so the row can be added in the correct place later. The filter is similar as the delete but instead of including things that exist, it includes anything that doesn't exist. This depends on null being effectively the same as false (i.e !null evaluates as true). Adding rows is done by using HTML, which is faster than creating elements/nodes individually.
let clientel = {
socket101: ['Rick', '192.590.49.1', 'Win10', 'Norway', '15:49.00'],
socket102: ['Anthony', '192.90.897.0', 'Win7', 'Negritine', '19:19:38']
};
function init() {
const table = document.getElementById('table-body');
// remove anything that doesn't have a row in the clientel map
[...table.rows].filter( (row) => !clientel[row.getAttribute('data')] )
.forEach( ({rowIndex}) => table.deleteRow(rowIndex - 1) )
// add anything that doesn't exist in the table
Object.keys(clientel)
.map( (key, index) => [ key, index ] )
.filter( ([key, index]) => !table.querySelector(`tr[data="${key}"]`) )
.forEach( ([key, index]) => {
var row = table.insertRow(index)
row.setAttribute('data', key);
row.innerHTML = clientel[key].map( value => `<td>${value}</td>` ).join("");
});
}
document.addEventListener("DOMContentLoaded", init);
</script>
<div id="table">
<table>
<thead>
<tr>
<th>Name</th>
<th>IP</th>
<th>OS</th>
<th>Country</th>
<th>Connected Since</th>
</tr>
</thead>
<tbody id="table-body">
<tr data="socket101">
<td>Rick</td>
<td>192.423.41.5</td>
<td>Win 7</td>
<td>Bulgaria</td>
<td>A few moments</td>
</tr>
<tr data="socket103">
<td>Whoever</td>
<td>127.0.0.1</td>
<td>OS/1</td>
<td>The Moon</td>
<td>Whatever</td>
</tr>
</tbody>
</table>
</div>
</body>
Suppose you have a html table of the
<form id="myForm">
<table id="myTable">
<tr>
<th>One</th>
<th>Two</th>
<th>Three</th>
</tr>
<tr>
<td>Alpha</td>
<td>Bravo</td>
<td>X</td>
</tr>
<tr>
<td>Charlie</td>
<td>Delta</td>
<td>X</td>
</tr>
<tr>
<td>Echo</td>
<td>Foxtrot</td>
<td>X</td>
</tr>
</table>
</form>
Reset
I have the following javascript
var table = document.getElementById('myTable');
var form = document.getElementById('myForm');
var formSave = form.innerHTML;
function remove(rowID)
{
table.deleteRow(rowID);
}
function reset()
{
form.innerHTML = formSave;
}
For some reason, the remove() function works fine, but after using the reset() function, it no longer works. Can anyone tell me why this is?
As var table is a live 'Element object' it's properties are updated each time you delete a row. By the time you deploy the reset() function var table references less Children than the restored HTML. Opening the console will show you have an indexing error on subsequent uses of the function bound to "X".
You can remedy this by re-acquiring the element in the reset function, like so...
var table = document.getElementById('myTable');
var form = document.getElementById('myForm');
var formSave = form.innerHTML;
function remove(rowID) {
table.deleteRow(rowID);
}
function reset() {
form.innerHTML = formSave;
/* re-acquire 'new' (inserted) table */
table = document.getElementById('myTable');
}
Hope that helped :)
I would like to split this entire table into three sub tables using Javascript. Each table should retain it's header information.
I cannot adjust the id's or classes as they are generated by a web application, so I need to make do with what is available.
I've been trying to crack this with Jfiddle for quite awhile and am getting frustrated. I'm pretty new to Javascript, but can't image this would require a lot of code. If anyone knows how to split this apart by row size as well (i.e. Split Table up, but selectively), that would be appreciated as well.
I'm limited to Javascript and Jquery 1.7.
<div id="serviceArray">
<table border="1" class="array vertical-array">
<thead>
<tr>
<th>#</th>
<th>Savings</th>
<th>Expenses</th>
<th>Savings</th>
<th>Expenses</th>
<th>Savings</th>
<th>Expenses</th>
</tr>
</thead>
<tbody>
<tr>
<td>Sum</td>
<td>$180</td>
<td>$500</td>
<td>$300</td>
<td>$700</td>
<td>$600</td>
<td>$1000</td>
</tr>
<tr>
<td>Home</td>
<td>$100</td>
<td>$200</td>
<td>$200</td>
<td>$300</td>
<td>$400</td>
<td>$500</td>
</tr>
<tr>
<td>Work</td>
<td>$80</td>
<td>$300</td>
<td>$100</td>
<td>$400</td>
<td>$200</td>
<td>$500</td>
</tr>
</tbody>
</table>
</div>
Did you mean like this?
var tables = $('#serviceArray table tbody tr').map(function () { //For each row
var $els = $(this).closest('tbody') //go to its parent tbody
.siblings('thead').add( //fetch thead
$(this) //and add itself (tr)
.wrap($('<tbody/>')) //wrapping itself in tbody
.closest('tbody')); //get itself with its tbody wrapper
return $els.clone() //clone the above created steps , i.e thead and tbody with one tr
.wrapAll($('<table/>', { //wrap them all to a new table with
'border': '1', //attributes.
'class': 'array vertical-array'
})
).closest('table'); //get the new table
}).get();
$('#serviceArray table').remove();
$('body').append(tables); //append all to the table.
Demo
Or just simply clone the table and remove all other trs from tbody except this one and add it to DOM (Much Shorter Solution).
var tables = $('#serviceArray table tbody tr').map(function (idx) {
var $table = $(this).closest('table').clone().find('tbody tr:not(:eq(' + idx + '))').remove().end();
return $table;
}).get();
Demo
Each of the methods used has documentation available in web and you can use this to work out something yourself to what you need.
You can use simple Javascript for table creation and it will generate rows according to your returned response from api.
var tableHeader = this.responseJsonData.Table_Headers;
var tableData = this.responseJsonData.Table_Data;
let table = document.querySelector("table");
function generateTableHead(table, data) {
//alert("In Table Head");
let thead = table.createTHead();
let row = thead.insertRow();
for (let key of data) {
let th = document.createElement("th");
let text = document.createTextNode(key);
th.appendChild(text);
row.appendChild(th);
}
}
function generateTable(table, data) {
// alert("In Generate Head");
for (let element of data) {
let row = table.insertRow();
for (key in element) {
let cell = row.insertCell();
let text = document.createTextNode(element[key]);
cell.appendChild(text);
}
}
}