Save each table column in a variable - javascript

For a jQuery plugin I need to add / remove classes to table columns. To do that I want to save each table column (multiple <td>) in its one variable once. The HTML for the table looks more or less like this:
<table>
<tr>
<td>Column 1</td>
<td>Column 2</td>
<td>Column 3</td>
</tr>
<tr>
<td>Column 1</td>
<td>Column 2</td>
<td>Column 3</td>
</tr>
</table>
In the end I want an array like $tableColumn[] or something, so that I can just add a class to my first column with $tableColumn[ 0 ].addClass('test');.
I could loop through each <tr> and <td>, but I'm not sure how to add multiple td to the same variable? Is there any other and better (e.g better performance) way to do that?
var $tableColumn = [];
$('table tr').each(function() {
// Loop through all rows
$( this ).find('td').each(function( idx ) {
// If I do something like this, there's only one td in my array
// Probably there is a better way to do this without needing to have two 'each' functions
$tableColumn[ idx ] = $( this );
});
});

First of, why is there two table ? You don't need to have a table tag for each row.
For your question and since you use jquery you can try something like this : (by using CSS3 selector)
$('table tr td:nth-child(' +columnNumber +')').addClass( className )
The nth-child selector will effectively select the columnNumber child of each row (tr) and therefore $('table tr td:nth-child(columnNumber)') get the columnNumber-th column of the table.
jsBin : http://jsbin.com/qisosado/2/edit?html,css,js,output

You could use nth-child to create an array of jQuery selections.
var i,
columns = [],
nColumns = $('table tr:first td').length;
for(i = 1; i <= nColumns; i ++) {
columns.push($('td:nth-child(' + i + ')'));
}
columns[0].addClass('a');
columns[1].addClass('b');
http://jsfiddle.net/gb0y0y6g/
Alternatively, check out the col tag.

i have created a jsfiddle for you..
for single column in row:-
code:-
var tableColumn = [];
$(document).ready(function() {
$('table tr td').each(function() {
tableColumn.push($(this));
});
//access the td from the array
tableColumn[0].addClass("yellow")
});
working example:-
http://jsfiddle.net/zoohcveh/12/
for all columns in row:-
code:-
var tableColumn = [];
$(document).ready(function() {
$('table tr').each(function() {
tableColumn.push($(this));
});
//access all the td from the array
tableColumn[0].addClass("yellow")
});
working example:-http://jsfiddle.net/zoohcveh/13/
thanks

You could use a column group if you're trying to do column specific things, like changing the background color of every cell in a column.
You can also use jQuery selectors to get a specific group of cells out of a collection.
jsbin: http://jsfiddle.net/pqm2gbqz/
HTML:
<button>Toggle</button>
<table>
<colgroup>
<col />
<col />
<col />
</colgroup>
<tbody>
<tr>
<td>Column 1</td>
<td>Column 2</td>
<td>Column 3</td>
</tr>
<tr>
<td>Column 1 row 2</td>
<td>Column 2 row 2</td>
<td>Column 3 row 2</td>
</tr>
</tbody>
</table>
JS:
var colgroup = document.querySelectorAll('col'),
button = document.querySelector('button'),
$tds = $("table").find("td")
;
button.addEventListener('click', function(e) {
e.preventDefault();
colgroup.item(0).classList.toggle('some-class');
$tds.filter(":last-of-type").toggleClass('hide');
});
CSS:
.some-class {
background: green;
}
.hide {
display: none;
}

Related

Vuejs - tr row not showing 100% when adding display block

In my VuewJS application, I want to be able to click a row and show/hide the row below. However, when I do that I get a weird bug were the row below only fills one column width.
Here is my table structure:
NOTE: This table is generated dynamically.
The top row with 4 columns has an attribute of id and the long row that fills up 4 columns has a a data attribute data-body-id.
<tr v-bind:key="data.id" v-bind:id="index" v-on:click="rowClick(index)">
<td>Col 1</td>
<td>Col 2</td>
<td>Col 3</td>
<td>Col 4</td>
</tr>
<tr v-bind:key="data.id" v-bind:data-body-id="index">
<td colspan="4">Col 5 (This is a really long 4 colspan row ..............)</td>
</tr>
which computes as:
<tr data-v-1a25d82d="" id="0">
<td data-v-1a25d82d="">Col 1</td>
<td data-v-1a25d82d="">Col 2</td>
<td data-v-1a25d82d="">Col 3</td>
<td data-v-1a25d82d="">Col 4</td>
</tr>
<tr data-v-1a25d82d="" data-body-id="0">
<td data-v-1a25d82d="" colspan="4">Col 5 (This is a really long 4 colspan row ..............)</td>
</tr>
in my rowClick(index) method I have:
methods: {
rowClick(id) {
var dataId = "data-body-id='" + id + "'";
var row = document.querySelector('[' + dataId + ']');
row.style.display = 'block';
}
}
When I click a row, the row below is visible but it shows like so:
If I use the developer inspector and find the attribute and uncheck the display: none; that is set in the CSS initially to hide the row it shows perfectly.
What is going on and how do I fix it?
When trying to show dynamic table rows that are hidden please use:
display: 'table-row',
so in your case:
row.style.display = 'table-row';

How do I target the nodes of a child of a child that I created through JavaScript?

I'm creating a table with JavaScript. It's located in a Div that has a name. It creates a table, which creates a tbody, which then has a number of td and tr.
I'm trying to target those td and tr with an event listener so that when I hover over them, they switch background color.
I've tried a few things, I put two in the code.
So yeah, how do I target the JavaScript created cells and make them change color on hover?
HTML
<div id="padDiv">
<!-- The JS pad goes here -->
</div>
Javascript #1
table.addEventListener("mouseover", () => {
event.target.style.backgroundColor = "block";
})
/* The code that creates the td and tr has this in it: */
let tbl = document.createElement("table");
let table = document.getElementsByClassName("table");
padDiv.appendChild(tbl);
Javascript #2
let table = document.getElementsbyId("padDiv").childNodes[0];
table.addEventListener("mouseover", () => {
event.target.style.backgroundColor = "block";
})
That last one I thought would make sense, because using...
padDiv.addEventListener("mouseover", () => {
event.target.style.backgroundColor = "block";
})
allowed me to color the cells like I wanted, but the whole div became black if I hovered over an area that was the div, but not occupied by a cell (margins).
So yeah, how do I target a the td and tr that are created alongside my table, considering the last thing that has a name when the page is created is padDiv?
Edit: The color needs to stay around until I hit a reset button.
Here is a way to alter background color with a 'mouseenter' listener attached to every td element in the tbody. It uses the Id of a table to dig in and find all of the relevant elements to apply the listener to.
When you want to clear the background color simply loop through your cells and set their background colors back to "initial".
var table = document.getElementById("StickyHighlight");
var body = table.getElementsByTagName("tbody");
var cells = body[0].getElementsByTagName("td");
function addHoverListener() {
for(var i = 0; i < cells.length; i++) {
cells[i].addEventListener("mouseenter", (e) => {
e.target.style.background = "cyan";
});
}
}
function reset() {
for(var i = 0; i < cells.length; i++){
cells[i].style.background = "initial";
}
}
addHoverListener();
thead {
background: black;
color: white;
}
<button onclick="reset()">Reset</button>
<table id="StickyHighlight">
<thead>
<tr>
<td>Col 1</td>
<td>Col 2</td>
<td>Col 3</td>
</tr>
</thead>
<tbody>
<tr>
<td>Thing 1</td>
<td>Thing 2</td>
<td>Thing 3</td>
</tr>
<tr>
<td>Thing 1</td>
<td>Thing 2</td>
<td>Thing 3</td>
</tr>
<tr>
<td>Thing 1</td>
<td>Thing 2</td>
<td>Thing 3</td>
</tr>
</tbody>
</table>

Select the first cell of each row placed after a merged cell using JavaScript/jQuery

I have a table with class evo-table, which has two cells of row span of 4, followed by four rows with two cells each (Image). I want to select the first cell of each of these rows using JavaScript. I know I could simply add classes to cells and style it using CSS but I'm restricted to the Table structure below. I am able to select and add CSS to the first cell of the first row using $(".highlight").next().css("background","lightgreen"); but I'm not able to select the first cell of the rest of the rows. Here's the code:
HTML: (This is a DEMO only)
<table class="evo-table">
<tr>
<td rowspan="4">Merged Cell 1</td>
<td rowspan="4" class="highlight">Merged Cell 2</td>
<td>Unmerged Cell 1</td>
<td>Unmerged Cell 2</td>
</tr>
<tr>
<td>Unmerged Cell 3</td>
<td>Unmerged Cell 4</td>
</tr>
<tr>
<td>Unmerged Cell 5</td>
<td>Unmerged Cell 6</td>
</tr>
<tr>
<td>Unmerged Cell 7</td>
<td>Unmerged Cell 8</td>
</tr>
<table>
jQuery/JavaScript:
var tableObj = $(".evo-table");
var mergeLength = $(".evo-table .highlight").attr("rowspan");
var firstRowAfterHighlight = $(".evolution-table .highlight").parent().next().index + 1;
$(".highlight").next().css("background","lightgreen");
for (count = 0; count < mergeLength; count = count + 1) {
$(".evolution-table tr:nth-child(" + (firstRowAfterHighlight + count) + ") td:first-child:not(.highlight)").css("background-color", "green")
}
I am using the rowspan value of .highlight cell to find the number of rows (I could use $(".evo-table tr").length; to get it but the previous one is more useful in my case as I want to select rows which are immediately to the right of the cell) and I'm finding the index of the row after first row and using count variable of the for statement to move on to the next row, and using the :first-child selector on td to select the first cell of every row. The code doesn't seem to work.
jsFiddle
Please reply if you spot any errors in my code, need more details or have a solution. Thank you.
I used the .each function to iterate over every row. And then I used teh :not selector to ignore elements with the attribute [rowspan].
$(".evo-table tr").each(function () {
$(this).find("td:not([rowspan]):first").css("background-color", "red")
});
* {
font-family:Arial;
}
.evo-table {
border-collapse:collapse;
border:1px solid lightgrey;
}
.evo-table td {
padding:4px;
border: 1px solid lightgrey;
}
.highlight {
background-color:yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="evo-table">
<tr>
<td rowspan="4">Merged Cell 1</td>
<td rowspan="4" class="highlight">Merged Cell 2</td>
<td>Unmerged Cell 1</td>
<td>Unmerged Cell 2</td>
</tr>
<tr>
<td>Unmerged Cell 3</td>
<td>Unmerged Cell 4</td>
</tr>
<tr>
<td>Unmerged Cell 5</td>
<td>Unmerged Cell 6</td>
</tr>
<tr>
<td>Unmerged Cell 7</td>
<td>Unmerged Cell 8</td>
</tr>
<table>
<div style="font-size:12px;color:lightgrey;">
Yellow = .highlight class; Green = Selected using jQuery;
</div>
If you just want to do this for styling, you don't need javascript, you can do it with plain CSS3:
td[rowspan] + td:not([rowspan]), tr > td:not([rowspan]):first-child {
background: red;
}
It selects a td without a rowspan that directly follows after a td with the rowspan attribute (the first tr) and all first td in a tr that do not have a rowspan attribute (all other tr).
If you want it in JavaScript, you can use the same CSS selector with jQuery. No need to loop over the table rows:
$('td[rowspan] + td:not([rowspan]), tr > td:not([rowspan]):first-child')

How can I loop through all elements of a certain type through jQuery?

There are some similar questions, but mine is a little bit more specific.
I have a table element with an id of "myTable" and some tr elements inside it (let's say the tr elements are 2).
<table id="myTable">
<tr>
<td>Row 1</td>
</tr>
<tr>
<td>Row 2</td>
</tr>
</table>
If I try to see the number of rows in the #myTable table element, by writing
var numberOfRows = $("#myTable tr").length;
I always have 1 in the numberOfRows variable.
It only works when I add a class to all the tr elements.
<table id="myTable">
<tr class="myRows">
<td>Row 1</td>
</tr>
<tr class="myRows">
<td>Row 2</td>
</tr>
</table>
Let's say the class is "myRows" and write the following:
var numberOfRows = $("#myTable .myRows").length;
Then, I get the right number - 2.
So, my question is how can I get the number of certain elements or loop through them if they are not distinguished by a class (like in the example above)?
you can use like :
$('#myTable > tbody > tr').each(function() {...code...});
Pure JavaScript that also works in all meyor browsers
var rows=document.getElementById("myTable").rows;
for(var rowIndex=0;rowIndex<rows.lenght;rowIndex++){
//now do everything with tr $(rows[rowIndex]).height(80)
}

Set colspan/rowspan for a cell

I have a table and I want to change colspan/rowspan property of a cell on runtime. Here is an example:
<html>
<head>
<script type="text/javascript">
function setColSpan() {
document.getElementById('myTable').rows[0].cells[0].colSpan = 2
}
</script>
</head>
<body>
<table id="myTable" border="1">
<tr>
<td>cell 1</td>
<td>cell 2</td>
</tr>
<tr>
<td>cell 3</td>
<td>cell 4</td>
</tr>
</table>
<form>
<input type="button" onclick="setColSpan()" value="Change colspan">
</form>
</body>
</html>
My problem is that the cells shift. Am I supposed to remove the cells over which the cell in question spans?
I can I do without removing?
I want to implement a simple spreadsheet. For now I managed to be able to select a rectangular range of cells and show a menu with a "Merge selected cells" option. I would like to be able to "unmerge" cells, so it would be good to span cells without having to remove other cells.
I think you need to delete the cell. Check with following code. What i did was removed the entire row and added new row with new column span
function setColSpan() {
var table = document.getElementById('myTable');
table.deleteRow(0);
var row = table.insertRow(0);
var cell = row.insertCell(0);
cell.innerHTML= "cell 1"
cell.colSpan = 2
}
The cells shift because that's what you're telling it to do. You're defining a table like this:
<tr>
<td colspan="2">cell 1</td>
<td>cell 2</td>
</tr>
<tr>
<td>cell 3</td>
<td>cell 4</td>
</tr>
So the shift you're seeing is what I would expect.
If you want to merge cells, you would have to take the contents of all the merged cells, concat them into a single cell, and remove the rest. For the trivial example, it'd go like this:
function setColSpan() {
var myTable = document.getElementById('myTable');
var cell2html = myTable.rows[0].cells[1].innerHTML;
myTable.rows[0].deleteCell(1);
myTable.rows[0].cells[0].innerHTML = myTable.rows[0].cells[0].innerHTML + ' ' + cell2html;
myTable.rows[0].cells[0].colSpan = 2;
}
However a more robust solution is...kind of complicated. Especially if you want the ability to unmerge. You'd have to preserve the information of the old cell structure somehow...possibly with putting something like <span class="oldCell">cell 2</span> around merged data? And then checking for the existence of "oldCell" spans when unmerging? But then you would have to preserve that information through user edits. And figure out what that means for merging across rows and columns. And also figure out what that means for overlapping merges.

Categories

Resources