I have a table which I want the first column to not move when I am scrolling horizontally. This code below works great for the first column of td's but does not work for the tr's. I have stepped through the code and it all appears to set the values I am expected, but the tr cell does not move with the td cells.
window.onscroll = function()
{
var scrollPosX = window.scrollX;
var theTable = document.getElementById("tablename"),
thead = theTable.getElementsByTagName("thead")[0];
tbody = theTable.getElementsByTagName("tbody")[0];
hrCell = thead.getElementsByTagName("tr")[0];
hrCell.style.left = scrollPosX;
rCells = tbody.getElementsByTagName("td");
for(var i = 0; i < rCells.length; i++)
{
rCells[i].style.left = scrollPosX;
}
}
JQuery is not an option in this problem as the program I am working on does not support it.
<style>
table
{
border: solid black 1px;
}
td{
min-width: 300px;
border: solid black 1px;
}
#run_gen_table td:first-child, #run_gen_table th:first-child
{
background-color: white;
position: relative;
}
</style>
<table id="tablename">
<thead id="headname">
<tr><th>Run No.</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th><th>9</th><th>10</th></tr>
</thead>
<tbody id="bodyname">
<tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td></tr>
</tbody>
</table>
I have not tested it but your code would alter all the td elements, not just the first column. A better approach would be to use document.querySelector() to select the first td and th elements.
window.onscroll = function()
{
var scrollPosX = window.scrollX;
var rCells = document.querySelector("#tablename th:first-child, #tablename td:first-child");
for(var i = 0; i < rCells.length; i++)
{
rCells[i].style.left = scrollPosX;
}
}
Related
I am trying to figure out how to make all 5 columns and rows searchable. At the moment it only searches via the first column (DATE). Could someone please assist me with possibly making it search all the columns and rows please? I have included the HTML, CSS and javascript to try to provide as much information as possible.
function myFunction() {
// Declare variables
var input, filter, table, tr, td, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
// Loop through all table rows, and hide those who don't match the search query
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
#myInput {
background-image: url('/css/searchicon.png'); /* Add a search icon to input */
background-position: 10px 12px; /* Position the search icon */
background-repeat: no-repeat; /* Do not repeat the icon image */
width: 100%; /* Full-width */
font-size: 16px; /* Increase font-size */
padding: 12px 20px 12px 40px; /* Add some padding */
border: 1px solid #ddd; /* Add a grey border */
margin-bottom: 12px; /* Add some space below the input */
}
#myTable {
border-collapse: collapse; /* Collapse borders */
width: 100%; /* Full-width */
border: 1px solid #ddd; /* Add a grey border */
font-size: 18px; /* Increase font-size */
}
#myTable th, #myTable td {
text-align: left; /* Left-align text */
padding: 12px; /* Add padding */
}
#myTable tr {
/* Add a bottom border to all table rows */
border-bottom: 1px solid #ddd;
}
#myTable tr.header, #myTable tr:hover {
/* Add a grey background color to the table header and on hover */
background-color: #f1f1f1;
}
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names..">
<table id="myTable">
<tr class="header">
<th style="width:20%;">Date</th>
<th style="width:20%;">Home</th>
<th style="width:20%;">Time</th>
<th style="width:20%;">Away</th>
<th style="width:20%;">City</th>
</tr>
<tr>
<td>08/01/2018</td>
<td>SPAIN</td>
<td>16:30 ET</td>
<td>USA</td>
<td>BARCELONA</td>
</tr>
<tr>
<td>08/02/2018</td>
<td>BOLIVIA</td>
<td>18:30 ET</td>
<td>PORTUAL</td>
<td>MADRID</td>
</tr>
<tr>
<td>08/03/2018</td>
<td>PUERTO RICO</td>
<td>18:30 ET</td>
<td>CANADA</td>
<td>CHICAGO</td>
</tr>
<tr>
<td>08/04/2018</td>
<td>MEXICO</td>
<td>19:30 ET</td>
<td>ENGLAND</td>
<td>LONDON</td>
</tr>
</table>
Using your existing code, loop through the table cells just as you loop through the table rows.
Below, I hide each row. For each row, if text in a cell matches the search term, that row is shown and the loop continues to the next row.
I'm also ignoring the table header by using tBodies to limit the search to <tr> elements that are within the first <tbody>. Alternatively, you could check that <td> elements exist in the row before searching; something like: if (tds.length) > 0.
function performSearch() {
// Declare search string
var filter = searchBox.value.toUpperCase();
// Loop through first tbody's rows
for (var rowI = 0; rowI < trs.length; rowI++) {
// define the row's cells
var tds = trs[rowI].getElementsByTagName("td");
// hide the row
trs[rowI].style.display = "none";
// loop through row cells
for (var cellI = 0; cellI < tds.length; cellI++) {
// if there's a match
if (tds[cellI].innerHTML.toUpperCase().indexOf(filter) > -1) {
// show the row
trs[rowI].style.display = "";
// skip to the next row
continue;
}
}
}
}
// declare elements
const searchBox = document.getElementById('searchBox');
const table = document.getElementById("myTable");
const trs = table.tBodies[0].getElementsByTagName("tr");
// add event listener to search box
searchBox.addEventListener('keyup', performSearch);
#searchBox {
box-sizing: border-box;
width: 100%;
font-size: 16px;
padding: 12px 20px 12px 40px;
border: 1px solid #ddd;
margin-bottom: 12px;
}
#myTable {
border-collapse: collapse;
width: 100%;
border: 1px solid #ddd;
font-size: 18px;
}
#myTable th,
#myTable td {
text-align: left;
padding: 12px;
}
#myTable th {
width: 20%;
}
#myTable tr {
border-bottom: 1px solid #ddd;
}
#myTable tr.header,
#myTable tr:hover {
background-color: #f1f1f1;
}
<input type="text" id="searchBox" placeholder="Search for names..">
<table id="myTable">
<thead>
<tr class="header">
<th>Date</th>
<th>Home</th>
<th>Time</th>
<th>Away</th>
<th>City</th>
</tr>
</thead>
<tbody>
<tr>
<td>08/01/2018</td>
<td>SPAIN</td>
<td>16:30 ET</td>
<td>USA</td>
<td>BARCELONA</td>
</tr>
<tr>
<td>08/02/2018</td>
<td>BOLIVIA</td>
<td>18:30 ET</td>
<td>PORTUAL</td>
<td>MADRID</td>
</tr>
<tr>
<td>08/03/2018</td>
<td>PUERTO RICO</td>
<td>18:30 ET</td>
<td>CANADA</td>
<td>CHICAGO</td>
</tr>
<tr>
<td>08/04/2018</td>
<td>MEXICO</td>
<td>19:30 ET</td>
<td>ENGLAND</td>
<td>LONDON</td>
</tr>
</tbody>
</table>
100% working for unlimited columns !
<input class="form-control" type="text" id="myInput" placeholder="Search ..." onkeyup="searchTableColumns()">
<table id="myTable">
.....
.....
.....
</table
function searchTableColumns() {
// Declare variables
var input, filter, table, tr, i, j, column_length, count_td;
column_length = document.getElementById('myTable').rows[0].cells.length;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
for (i = 1; i < tr.length; i++) { // except first(heading) row
count_td = 0;
for(j = 1; j < column_length-1; j++){ // except first column
td = tr[i].getElementsByTagName("td")[j];
/* ADD columns here that you want you to filter to be used on */
if (td) {
if ( td.innerHTML.toUpperCase().indexOf(filter) > -1) {
count_td++;
}
}
}
if(count_td > 0){
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
When you do tr[i].getElementsByTagName("td")[0];, you only select the date column, wich is why it only search in that one. You are going to have to loop through all the coumn and set a boolean to true if you find it at least once.
Something like that:
var found = false;
var td = tr[i].getElementsByTagName("td");
for(j = 0; j < td.length; j++) {
if (td[j].innerHTML.toUpperCase().indexOf(filter) > -1) {
//if found at least once it is set to true
found = true;
}
}
//only hides or shows it after checking all columns
if(found){
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
a compact version of the above code, credit to #showdev
/**
* HTML Search for any table
*
* #param element searchBox
* #param string tableBody
*/
function performSearch(searchBox,tableBody) {
let trs = $('#'+tableBody).find('tr');
// Declare search string
let filter = searchBox.value.toUpperCase();
// Loop through first tbody's rows
for (let rowI = 0; rowI < trs.length; rowI++) {
// define the row's cells
let tds = trs[rowI].getElementsByTagName("td");
// hide the row
trs[rowI].style.display = "none";
// loop through row cells
for (let cellI = 0; cellI < tds.length; cellI++) {
// if there's a match
if (tds[cellI].innerHTML.toUpperCase().indexOf(filter) > -1) {
// show the row
trs[rowI].style.display = "";
// skip to the next row
continue;
}
}
}
}
Use it like onkeyup="performSearch(this,'smsTableBody')"
I'm currently busy with a project that has an html table with games and years they are launched. I'm trying to create a button that when clicked will hide any row that wasn't launched in 2016.
So my thoughts behind this process are that I'll create a forloop to go through each row and column to find the year value and if it's 2016 leave it alone, if not, hide it.
However I'm having an issue on the looping part.
<script>
function GameSearchLoop() {
var table = document.getElementsByClassName(table);
if (table == null) {
console.log("Table Not Found");
}
else {
console.log("Table Found");
}
var rowLength = table.rows.length;
for (var z = 0; z < rowLength; z++) {
var cells = table.rows.item(z).cells;
var cellLength = cells.length;
console.log("Row Checked");
for (var x = 0; x < cellLength; x++) {
console.log("Column Checked");
}
}
//for (var r = 0, n = table.rows.length; r < n; r++) {
// console.log("Row Checked");
// for (var c = 0, m = table.rows[r].cells.length; c < m; c++) {
// alert(table.rows[r].cells[c].innerHTML);
// console.log("Column Checked");
// }
//}
}
</script>
I've got two different for loops here and neither of them seem to work.
The table is created slightly about this with the same script with the class table attached to it.
When running the code and hitting the button I do see "Table Found" in the console but after that I get a "Cannot read property 'length' of undefined at GameSearchLoop".
Thanks
getElementsByClassName returns a NodeList, a collection. You need the first of these elements:
var table = document.getElementsByClassName(table)[0];
assuming that table is in the first instance a variable containing a class-name, and that your table is the first, or only, one of these.
Or alternatively,
var rowLength = table[0].rows.length;
Better yet, give your table an ID and use getElementById.
I found it form W3schools i hope this will help
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
box-sizing: border-box;
}
#myInput {
background-image: url('/css/searchicon.png');
background-position: 10px 10px;
background-repeat: no-repeat;
width: 100%;
font-size: 16px;
padding: 12px 20px 12px 40px;
border: 1px solid #ddd;
margin-bottom: 12px;
}
#myTable {
border-collapse: collapse;
width: 100%;
border: 1px solid #ddd;
font-size: 18px;
}
#myTable th, #myTable td {
text-align: left;
padding: 12px;
}
#myTable tr {
border-bottom: 1px solid #ddd;
}
#myTable tr.header, #myTable tr:hover {
background-color: #f1f1f1;
}
</style>
</head>
<body>
<h2>I picked it from W3schools</h2>
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Year</th>
<th style="width:40%;">Country</th>
</tr>
<tr>
<td>2016</td>
<td>Germany</td>
</tr>
<tr>
<td>2017</td>
<td>Sweden</td>
</tr>
<tr>
<td>2016</td>
<td>UK</td>
</tr>
<tr>
<td>2018</td>
<td>Germany</td>
</tr>
<tr>
<td>2019</td>
<td>Canada</td>
</tr>
<tr>
<td>2010</td>
<td>Italy</td>
</tr>
<tr>
<td>2016</td>
<td>UK</td>
</tr>
<tr>
<td>2013</td>
<td>France</td>
</tr>
</table>
<script>
function myFunction() {
var input, filter, table, tr, td, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
</script>
</body>
</html>
insted of
var table = document.getElementsByClassName(table);
use
var table = document.getElementsByClassName('some class in string');
I have four tables of soccer players, one for goalkeepers, one for defenders, one for midfielders and one for attackers. I want the user to be able to change the position of a player so that he'll disappear from his current table and appear in another one without a page refresh.
The only method that I can think of is to have each player listed in all four tables but have him hidden for three of them. Then if he changes, I hide him in the current table and show him in another one.
I know how to achieve this, but it seems a bit heavy and I'm wondering if there's a more elegant solution.
You can use appendChild() in pure JavaScript to move a node from one place to another. The node is automatically removed from its old position in the DOM.
To quote the Mozilla Developer Network documentation on appendChild:
If the given child is a reference to an existing node in the document, appendChild() moves it from its current position to the new position (there is no requirement to remove the node from its parent node before appending it to some other node).
This means that a node can't be in two points of the document simultaneously. So if the node already has a parent, it is first removed, then appended at the new position.
The following snippet demonstrates the use of appendChild() to move rows between tables. Click on the move buttons to move an item from one table to the other.
window.onload = function () {
var data = {
like: ['vanilla', 'pistachio', 'squirrels', 'squash', 'mountains'],
dislike: ['chocolate', 'trucks', 'football', 'hard candy', 'valleys']
};
var tables = {};
var moveMe = function () {
this.table = tables[this.table === tables.like ? 'dislike' : 'like'];
this.table.tbody.appendChild(this.tr);
};
Object.keys(data).forEach(function (key) {
var container = document.createElement('div'),
table = tables[key] = document.createElement('table'),
tbody = table.tbody = document.createElement('tbody');
data[key].forEach(function (item) {
var tr = document.createElement('tr'),
td = document.createElement('td');
td.innerHTML = item;
tr.appendChild(td);
tbody.appendChild(tr);
var button = document.createElement('button');
button.innerHTML = 'move';
button.onclick = moveMe;
button.table = table;
button.tr = tr;
td.appendChild(button);
});
table.appendChild(tbody);
var header = document.createElement('h2');
header.innerHTML = key;
container.appendChild(header);
container.appendChild(table);
container.className = 'container';
document.getElementById('wrapper').appendChild(container);
});
};
* {
box-model: border-box;
}
body {
font-family: sans-serif;
}
#wrapper {
width: 450px;
}
.container {
display: inline-block;
width: 200px;
padding: 10px;
}
h2 {
margin: 5px 0;
color: #666;
}
table {
width: 200px;
border-collapse: collapse;
}
td {
color: #333;
padding: 10px;
border: 1px solid #bbb;
position: relative;
}
td button {
position: absolute;
right: 5px;
top: 5px;
border: 2px solid #ccc;
border-radius: 5px;
background: #fff;
font-size: 12px;
}
td button:hover {
outline: none;
border-color: #888;
cursor: pointer;
}
<div id="wrapper"></div>
You could also use table api to manipulate your tables, here is a sample:
moving 1,1,1 element to 3,1,1
var tables = document.querySelectorAll("table")
var elementToMove = tables[0].rows[0].cells[0]
var destination = tables[2].rows[0].cells[0]
destination.innerHTML = elementToMove.innerHTML
elementToMove.innerHTML = ""
<table>
<tr>
<td>1,1,1</td>
<td>1,1,2</td>
<td>1,1,3</td>
</tr>
<tr>
<td>1,2,1</td>
<td>1,2,2</td>
<td>1,2,3</td>
</tr>
<tr>
<td>1,3,1</td>
<td>1,3,2</td>
<td>1,3,3</td>
</tr>
</table>
<br>
<table>
<tr>
<td>2,1,1</td>
<td>2,1,2</td>
<td>2,1,3</td>
</tr>
<tr>
<td>2,2,1</td>
<td>2,2,2</td>
<td>2,2,3</td>
</tr>
<tr>
<td>2,3,1</td>
<td>2,3,2</td>
<td>2,3,3</td>
</tr>
</table>
<br>
<table>
<tr>
<td>3,1,1</td>
<td>3,1,2</td>
<td>3,1,3</td>
</tr>
<tr>
<td>3,2,1</td>
<td>3,2,2</td>
<td>3,2,3</td>
</tr>
<tr>
<td>3,3,1</td>
<td>3,3,2</td>
<td>3,3,3</td>
</tr>
</table>
Note that i'm using innerHTML to access data, but you could identify whatever element you have in the cell and then use the appendChild method to move the element you need
For some reason, the input I created with the table is NOT AS LONG. I used normalize.css too, and all that did is made it slightly longer. I need it to fill the page and I have no idea where to even begin wording my google searches for such an issue.
Also, all of the css rules DO apply except for width (i think). My dynamically created input is just not as long as the others. Blows my mind.
function makeInput() {
var myInput = document.createElement("input");
myInput.type = "text";
myInput.value = "Here is where the quetsion goes";
return myInput;
}
function makeTable() { // make table with one row and one td
var myTable = document.createElement('table'); // Create table called myTable
var myRow = document.createElement('tr'); // create row called myTr
myTable.id = "myTalbe"
myTable.border = "0"
myTable.cellspacing = "2"
myTable.cellpadding = "0"
myTable.width = "100%"
myTable.type = "text"
var td1 = document.createElement('td'); // td1 for input
var td2 = document.createElement('td'); // td2 for button
var text1 = document.createTextNode('Here is my text');
td1.appendChild(makeInput()); // append makeInput();
td2.appendChild(makeButton()); // append my input form to td1
myRow.appendChild(td1);
myRow.appendChild(td2); // append td1 element to my table
myTable.appendChild(myRow); //
document.body.appendChild(myTable);
}
Game plan: makeInput() returns an input element. makeTable() puts it inside a <td>. makeTable() runs under $(document).ready (jQuery).
I have 5 other inputs on the page. All of which are managed by this:
input[type="text"] {
height: 30px;
display: block;
margin: 0;
width: 98%;
font-family: sans-serif;
font-size: 18px;
appearance: none;
box-shadow: none;
border-radius: none;
}
table tr td input[type="text"] {
height: 30px;
display: block;
margin: 0;
width: 98% !important;
font-family: sans-serif;
font-size: 18px;
appearance: none;
box-shadow: none;
border-radius: none;
}
You try this css....
Tables come with spacing between cells, borders, and padding on cells. Reset those to 0 and it should fill the available space, matching the other inputs. Since there is a cell next to the inputs they will not be the exact same width, since the other cell pushes it to be narrower, but they will line up at least.
function makeInput() {
var myInput = document.createElement("input");
myInput.type = "text";
myInput.value = "Here is where the quetsion goes";
return myInput;
}
function makeTable() { // make table with one row and one td
console.log("Make a table");
var myTable = document.createElement('table'); // Create table called myTable
var myRow = document.createElement('tr'); // create row called myTr
myTable.id = "myTalbe"
myTable.border = "0"
myTable.cellspacing = "2"
myTable.cellpadding = "0"
myTable.width = "100%"
myTable.type = "text"
var td1 = document.createElement('td'); // td1 for input
var td2 = document.createElement('td'); // td2 for button
var text1 = document.createTextNode('Here is my text');
td1.appendChild(makeInput()); // append makeInput() to td1
td2.appendChild(makeButton()); // append makeButton() to td2
myRow.appendChild(td1); // append td1 to the row
myRow.appendChild(td2); // append td2 to the row
myTable.appendChild(myRow); // append the row to the table
document.body.appendChild(myTable); // append the table to the body
}
function makeButton() {
var myButton = document.createElement('button');
var txt = document.createTextNode('Test');
myButton.appendChild(txt);
return myButton;
}
$(document).ready(makeTable);
button, input[type="text"] {
width: 100%;
box-sizing: border-box;
height: 30px;
line-height: 30px;
font-family: sans-serif;
font-size: 18px;
}
input[type="text"] {
display: block;
margin: 0;
appearance: none;
box-shadow: none;
border-radius: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
td {
padding: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" value="Made on load" />
<input type="text" value="This one was made on load too" />
I want a table displayed as a grid.The table is held by a div. In case it extends the div's dimension I want to be able to scroll the div in order to see the entire table.The table content is generated in the script. I also defined some css classes.
var rows = 500;
var cols = 500;
PopulateGrid();
function PopulateGrid() {
var table = document.getElementById("GridTable");
for (i = 0; i < rows; i++) {
var tr = document.createElement('TR');
for (j = 0; j < cols; j++) {
var td = document.createElement('TD')
tr.appendChild(td);
}
table.appendChild(tr);
}
}
td {
border: 1px solid black;
height: 50px;
width: 50px;
}
table {
border-spacing: 0px;
}
.GridContainer {
height: 650px;
width: 1447px;
overflow: scroll;
}
<head runat="server">
<title></title>
</head>
<body>
<div class="GridContainer">
<table id="GridTable"></table>
</div>
</body>
Unfortunately the dt width is scaled while its height seems to correspond with the value defined in css. Am I missing some css property?
Width on TD elements is a bit odd, and the rules can be a bit complex. You are thinking that the table width should be the sum of the individual td elements, but it works in reverse. The minimum required size for the table is determined as well as the size it would like it to be, then it tries to determine sane values for the widths of the TDs. The following works, and it would also work if you set the table width to 500*50px (25000px).
var rows = 500;
var cols = 500;
PopulateGrid();
function PopulateGrid() {
var table = document.getElementById("GridTable");
for (i = 0; i < rows; i++) {
var tr = document.createElement('TR');
for (j = 0; j < cols; j++) {
var td = document.createElement('TD')
tr.appendChild(td);
}
table.appendChild(tr);
}
}
td {
border: 1px solid black;
height: 50px;
width: 50px;
min-width: 50px;
}
table {
border-spacing: 0px;
}
.GridContainer {
height: 650px;
width: 1447px;
overflow: scroll;
}
<head runat="server">
<title></title>
</head>
<body>
<div class="GridContainer">
<table id="GridTable"></table>
</div>
</body>