Jquery, selection several TRs in a table - javascript

I have a html table which has several rows - lets say 17 for this example. On row 2, 9 and 15 I have some BOLD text which are basically headers for the rows after it. I've used the following code to add an IMAGE after each header:
$("#tblResults tr.lGreyBG td span.gridTXT b").each (function(index) {
$(this).after(" <img class='ChartButton' id='c"+ index +"'src='Images//chart_bar.png' alt='Chart' width='20' />");
});
I also have the following bit of code which binds a click event to each of the chart buttons.
$("img.ChartButton").click(function(){
alert ($(this).attr("id")); // THIS LINE WILL BE REPLACED
});
At the moment, it simply displays the ID of the chart button. What I need to do is replace the alert to pull back the rows afters the header row that was clicked, upto the next header row, of until the end of the table, (whichever comes first). So if the first button was clicked then rows 3 to 8 will be pulled back. Once I have these I can then iterate through each of the TD cells to look at the data in the table.
Many thanks for any help on what "selectors" I need to use to pull back the correct rows. Also note that this needs to be dynamic as other tables will have different number of rows.
Thanks
H

If there is a set of rows that belong together my first instinct would be to declare classes that help me select all of them at once e.g.
<tr class="group-1"> ... </tr>
<tr class="group-1"> ... </tr>
<tr class="group-2"> ... </tr>
<tr class="group-2"> ... </tr>
...
Or multiple theads and tbodies as Tomalak suggests.
If this is not possible and you want to do this using jQuery you can select all the rows after the header using nextAll(). You'll just have to filter out all rows that are after the next heading.
var nextBlockAndTheRest = $(this). // create jQuery object out of this img
closest("tr"). // find the parent tr
nextAll("tr.lGreyBg"). // find all next lGreyBg rows
first("td span.gridTXT b"). // find the first with b
nextAll(). // select all following rows
andSelf(); // add the row with b
var thisBlock = $(this). // create jQuery object out of the img
closest("tr"). // find the parent tr
nextUntil("td span.gridTXT b"). // select everything after the tr
andSelf(). // add the current block heading
not(nextBlockAndTheRest); // remove all the rest of the rows
jsFiddle

// notice that use after() directly, without each()
$("#tblResults tr.lGreyBG td span.gridTXT b").after(function (index) {
return "<img class='ChartButton' id='c"+ index +"'src='Images//chart_bar.png' alt='Chart' width='20' />";
});
$("#tblResults").delegate("img.ChartButton", "click", function () {
var currentRows = $(this).closest("tr").nextUntil("tr:has(span.gridTXT b)");
});
BTW: You definitely should think about a more semantic markup using multiple <thead> and <tbody> tags if your table has multiple heads and bodies.
$("#tblResults thead span.gridTXT b").after(function (index) {
return "<img class='ChartButton' id='c"+ index +"'src='Images//chart_bar.png' alt='Chart' width='20' />";
});
$("#tblResults").delegate("img.ChartButton", "click", function () {
var currentRows = $(this).closest("thead").next("tbody").find("tr");
});
Edit: Changed answer to use nextUntil().

Related

How to update the row indexes of a dynamic table when a row is deleted? [duplicate]

I'm working on making a dynamic HTML table using jQuery. In a table, my user has two interactions:
Append a row
Remove a specific row
The problem with numbering the rows is that if a user removes a specific row, all of the rows following that row need to be renumbered. I would have to select all rows following the removed row and subtract their number by 1.
Is there a better way to go about this?
EDIT: Here's a JSFiddle demonstrating the problem: http://jsfiddle.net/LNXae/2/
I'm aware that an ordered-list would automatically renumber my rows, but I'd rather use a table since the example I'm giving now is pretty boiled-down.
http://jsfiddle.net/mblase75/LNXae/1/
First, wrap the counter number in a <span> with a class for easy finding later:
$new_row.children('td').prepend('Row #<span class="num">' + ($new_row.index() + 1) + "</span>");
Then update all these spans with an .each loop after you remove the desired row. The first argument passed into .each's callback function is a zero-based index number, and the second is the HTML element:
var $row = $(this).closest('tr'),
$table = $row.closest('table');
$row.remove();
$table.find('tr').each(function(i, v) {
$(v).find('span.num').text(i + 1);
});
After the user has appended a row, or deleted one, you just need to iterate over the "number" cells. If we assume that you have a <td> element, we:
1) give them a nice ID, e.g. row_0, row_1, etc...
2) write a function to iterate over them:
function updateRows(){
$('[id*="row_"]').each(function(index){
$(this).html(index + 1); // add +1 to prevent 0 index.
};
};
I have written a jquery plugin which does exactly this, and you shouldnt need to "number" the rows per-se. All you need to do when deleting a row is to pass the index of the row being deleted.
eg, if you have a delete button in a row:
<table>
<tr>
<td> <input type="button" class="delete" value="delete this row" /></td>
</tr>
</table>
The jQuery might look like
$('.delete').click(function(){
var index = $(this).parents('tr').index();
// tell your plugin to delete row "index"
});
The method from my plugin which does this looks something like:
removeRow: function (index) {
return this.each(function () {
var $this = $(this);
var $tbody = $('tbody', $this);
var $tr = $('tr', $tbody).eq(index);
$this.trigger('rowRemoved', [$tr]);
$tr.remove();
});
}

Jquery Toggle Table Column Using a Better Method

I have a table with around 30 columns and the idea is to let the user select which columns to be hidden or shown. The reason for this is to let them select which columns will be visible when they print.
To tackle this problem, I have assigned a class name to each column and i'm using jQuery's toggle function. This works fine, but I was wondering if there is a better way to go about it that is more efficient and cleaner than what I am currently using. I have a separate function for each column and my code looks like this:
jQuery
function tablecolumn1toggle(){
$(".column1").toggle();
}
function tablecolumn2toggle(){
$(".column2").toggle();
}
function tablecolumn3toggle(){
$(".column3").toggle();
}
HTML Simplified
toggle column 1
toggle column 2
toggle column 3
<table class="table table-bordered" id="points_table">
<tbody>
<tr>
<th class="column1>Route</th>
<th class="column2">Location</th>
<th class="column3>Track</th>
</tr>
</tbody>
</table>
and so on..
I am using a button to call each toggle function, I will use checkboxes once I have the basic code working. So, is there a way for me to cut down the amount of code?
EDIT: Thank you all for your answers, it was really hard to pick a single answer but i'm grateful for all your input.
If you want to do it dynamically using checkboxes, add a data property to the checkbox
<input class='toggleColumns' type="checkbox" data-target="column1" />
<input class='toggleColumns' type="checkbox" data-target="column2" />
<input class='toggleColumns' type="checkbox" data-target="column3" />
<input class='toggleColumns' type="checkbox" data-target="column4" />
then add a change event on the checkbox:
$('.toggleColumns').on('change', function (e) {
// get the target for this checkbox and toggle it
var tableColumn = $(e.currentTarget).data('target');
$('.' + tableColumn).toggle();
});
Here is working fiddle: https://jsfiddle.net/9Ls49w97/
A bit of a late addition, but to add one more alternative: if you have multiple setups of this kind and you don't want to add classes each time, you can show or hide a column with something like $('tr *:nth-child(' + (ColumnIndex + 1) + ')', table).toggle();. Especially if you change the column order in the future, the class approach can come to bite you.
One step further, is not to define the checkboxes beforehand, but have JQuery create them on the fly. This is also easier in maintaining the page and with the added benefit that you can assign the column index while creating the input objects and don't have to add any special attributes in design time.
All in all, the html would be as light as possible (no classes or properties) and doesn't have to be maintained. An example where the checkboxes are added in a div:
var table = $('table'); //add an id if necessary
var cols = $('th', table); //headers
var div = $('<div>'); //new div for checkboxes
cols.each(function(ind){
$('<label>').text($(this).text()).append(
$('<input type="checkbox" checked=true>') //create new checkbox
.change(function(){
$('tr *:nth-child(' + (ind + 1) + ')', table).toggle();
})
).appendTo(div);
});
table.before(div); //insert the new div before the table
Fiddle
/* number is a parameter now */
function tablecolumntoggle(i){
$(".column"+i).toggle();
}
/* example to iteratly call */
for (var i = 1; i <= 3; i++) {
tablecolumntoggle(i);
};
Here's one way to make it simpler.
Give each button a data-col value and the matching column element(s) the same data-col value, then they can be paired in a simple function:
<button data-col='column1'>toggle</button>
<button data-col='total'>toggle</button>
<button data-col='other'>toggle</button>
<div class="col" data-col="column1">
column 1
</div>
<div class="col" data-col="total">
total column
</div>
<div class="col" data-col="other">
other
</div>
and code
$(function() {
$("button[data-col]").on("click", function() {
var col = $(this).data("col");
$(".col[data-col='" + col + "']").toggle();
});
})
Simple fiddle demo: https://jsfiddle.net/bb1mm0cp/
You Pass number 1,2,3 function
Try this
function tablecolumn1toggle(id){
$(".column"+id).toggle();
}
function call like this
tablecolumn1toggle(1); or
tablecolumn1toggle(2); or
tablecolumn1toggle(3);
OR
function tablecolumn1toggle(colum_name){
$(colum_name).toggle();
}
function call like this
tablecolumn1toggle(column1); or
tablecolumn1toggle(column2); or
tablecolumn1toggle(column3);

How to determine type of Html table column

I have a table with 3 columns.
is hidden and is containing "id" of selected row
is containing "product" name
is containing an yes/no denoting product is present or not
On Row click push the details to an array as
$("#Product_grid_wrapper table tr").click(function () {
//empty the array
selectedProduct = [];
$('#Product_grid_wrapper table tr').removeClass("row_selected");
$(this).find('td').each(function () {
selectedProduct.push($(this).text());
});
$(this).addClass("row_selected");
});
But I was asked to change the "yes/no" with an image.I did it perfectly. Now the third column is containing Image tag , with image setting at runtime using aspx
but the code
selectedProduct.push($(this).text());
will fail for 3rd column as it is containing the image.How to handle this case?
I am able to give a class="yes/no" to Image tag from Server.But how can I read this value as per above code.can I find the type of content of table col and use appropriate function
$(this).find('td').each(function () {
//if(type of content of td is image tag)
{
selectedProduct.push($(this).html());
//will extract "class " of image tag to get "yes/no" value
}
else{
selectedProduct.push($(this).text());
}
});
If you've added a class yes/no to the image, you could try this:
if($(this).find('img').length == 1) {
selectedProduct.push($(this).find('img').attr('class'));
}
Try html()instead of text()
selectedProduct.push($(this).html());
Try using attributes in your elements instead of hiding columns and missusing css-classes if possible. Maybe like this:
<tr id="123">
<td>_productName</td>
<td>
<img data-present="yes" src="..." />
</td>
</tr>
You can then use:
selectedProduct.push({id : $(this).id, present : $(this).find('img').data('present')});

Targeting Classes in Table Row

The code:
var table = document.getElementById('some-table');
var row = table.rows;
alert(row.length); // Returns number of rows
// Function to hide class on specific row when some action is performed
function someFunc(i) {
var elementToTarget = row[i].getElementsByClassName('some-class');
var otherElementToTarget = row[i].getElementsByClassName('some-other-class');
elementToTarget.style.display="none"; // Returns "elementToTarget.style
// is undefined"
otherElementToTarget.style.display="inline"; // Returns undefined
}
Basic table layout:
<table>
<tr>
<td>
<div class="some-class"></div>
<div class="some-other-class"></div>
</td>
</tr>
</table>
What I want to do: When a user triggers someFunc(), it hides some-class and displays some-other-class. But it only hides some-class for that particular row. Not all of the rows.
My Problem: It tells me that the elements in that row are undefined and I cannot perform any actions on them. It's very likely that I'm targetting those classes improperly.
Hopefully, I've been clear enough. If you need more clarification let me know.
Edit: There may not always be 'some-other-class' in the row. That's why I can't just target one of the divs. I need to know their row.
I'd refer you to the getElementsByClassName function's API. https://developer.mozilla.org/en-US/docs/Web/API/document.getElementsByName
Also, notice the name - Element*s*. It returns a list. And your function should treat it accordingly. so, e.g:
var elementToTarget = row[i].getElementsByClassName('some-class')[0];
var otherElementToTarget = row[i].getElementsByClassName('some-other-class')[0];
Check out this fiddle: http://jsfiddle.net/YD78S/

jQuery change all tr classes after specified one

I have a data table with alternating row background colors. I have an AJAX script to delete a row. I can't come up with a way to change the class of all the rows beneath the one that was deleted so that it alternates correctly again.
For example, considering the following:
`<tr id="1" class="row1">
<td>blah</td>
</tr>
<tr id="2" class="row2">
<td>blah</td>
</tr>
<tr id="3" class="row1">
<td>blah</td>
</tr>
<tr id="4" class="row2">
<td>blah</td>
</tr>`
Now, using my AJAX script, I remove id2, then id3 will move underneath id1 and they will have the same row color. I managed to make my script change the next tr class, but that doesn't really help because then it's just the same color as the one after that. I can't figure out how to iterate through all of the next tr's, and change their class accordingly.
What I have so far:
$('#news_' + id).fadeOut('slow');
var currtr = $('#news_' + id).attr('class');
var nexttr = $('#news_' + id).closest('tr').next('tr').attr('id');
$('#' + nexttr).removeClass($('#' + nexttr).attr('class'));
$('#' + nexttr).addClass(currtr);
You could just iterate over the visible<tr> elements, and remove the class from the even ones, and apply to the odd ones.
Something like this:
Example: http://jsfiddle.net/2CZdT/
$('tr:odd').addClass('odd');
$('td').click(function() {
$(this).parent().fadeOut(function() {
$(this).siblings('tr:visible').filter(':even').removeClass('odd')
.end().filter(':odd').addClass('odd');
});
});​
I have the click event on the <td>, so when one is clicked, it traverses up to the parent <tr> element, fades it out, the in the callback, it grabs all visible sibling <tr> elements, filters the even ones, removes the .odd class, then goes back and filters the odd ones, and adds the .odd class.
Note that this presumes there's a default class applied in your CSS, then you override the odd ones (or even ones) with the alternating class.
Easiest way is to go over the whole table again, e.g. add this after the fadeOut:
$('#id_of_your_table tr:even').addClass('even');
Edit: on second thought, that won't work since the row you faded still exists, but just isn't visible. You need to remove it from the DOM, or skip it when re-applying the zebra-effect. Example:
$('#news_' + id)
.fadeOut('slow')
.remove()
.closest('table')
.find('tr:even').addClass('even');
Or:
$('#news_' + id)
.fadeOut('slow')
.addClass('skip')
.closest('table')
.find('tr:not(.skip):even').addClass('even');
You can also target the table directly as in the first example, but you might as well move up from the faded row to the table its in.
You could use the next siblings selector to get all the rows following the one you are going to delete. Delete the desired row. Then, you should already have the following siblings, so just .each() them and change their class.
E.g.
var followingRows = $("#id2 ~ tr");
$("#id2").remove();
followingRows.each(function() {
if (this.is('.even')
this.removeClass('even').addClass('odd');
else
this.removeClass('odd').addClass('even');
});
Something close to that...
Let CSS do the work for you.
table tr:nth-child(2n+1) {
background-color: #eef;
}
no JavaScript required! =)
I would do something like this:
$('news_' + id).fadeOut('slow', function() {
$(this).remove();
});
var i = 1;
$('tr').removeClass().each(function() {
if (i == 1) {
$(this).addClass('row' + i);
i++;
} else {
$(this).addClass('row' + i);
i--;
}
});

Categories

Resources