How to set the index for a dynamically changing table? - javascript

I have created a form where you can add or delete table rows using javascript and jQuery. I would like to know how I can obtain and set the index for each table row such that sequence is maintained even if I were to delete and element from the middle of the table. The table is of the form:
<thead>
<tr>
<th>Index</th>
<th>Name</th>
<th>Property</th>
<th>Edit/Delete</th>
</tr>
</thead>
<tbody>
<tr>
<td class="index">Index goes here (1)</td>
<td>NameOne</td>
<td>PropOne</td>
<td><span class="edit">Edit Icon</span> <span class="delete">Delete Icon</span></td>
</tr>
<tr>
<td class="index">2</td>
<td>NameTwo</td>
<td>PropTwo</td>
<td><span class="edit">Edit Icon</span> <span class="delete">Delete Icon</span></td>
</tr>
<tr>
<td class="index">3</td>
<td>NameThree</td>
<td>PropThree</td>
<td><span class="edit">Edit Icon</span> <span class="delete">Delete Icon</span></td>
</tr>
</tbody>
Now what I want to achieve is if I were to delete the second row, the index of the previous third row should automatically change to 2 and if I were to add new element it should automatically take the index value of 3 and so on.
I tried to achieve this with:
function setIndex(){
$("td.index").each(function(index) {
$(this).text(++index);
});
}
But when I used the above function although the initial index when the elements were added printed properly the index wouldn't update properly when I called the function again after deleting or editing a row( I deleted the row using jQuery remove).
Also I am creating the new table rows with jQuery append().
I think that although I used remove() they don't get deleted completely as when I used a console.log("test") statement inside the setIndex() although "test" was only supposed to be printed twice(I had initially created 3 rows and deleted one of them) it go printed thrice signifying that there were 3 tr.index's.
Please help me solve the same.

You can use the CSS counter-reset and content properties.
The counter-reset property allows for automatic numbering of elements.
It works on any element.
The counter-reset property is used to reset a CSS counter to a given value.
It sets a named counter to a specific value.
body{
counter-reset: Serial; /* Set the Serial counter to 0 */
}
table{
border-collapse: collapse;
}
tr td:first-child:before{
counter-increment: Serial; /* Increment the Serial counter */
content:counter(Serial); /* Display the counter */
}
<table border="1">
<thead>
<tr>
<th>Automatic Serial number</th>
<th>Column 1</th>
<th>Column 2</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td>Column 1</td>
<td>Column 2</td>
</tr>
<tr>
<td></td>
<td>Column 1</td>
<td>Column 2</td>
</tr>
<tr>
<td></td>
<td>Column 1</td>
<td>Column 2</td>
</tr>
<tr>
<td></td>
<td>Column 1</td>
<td>Column 2</td>
</tr>
<tr>
<td></td>
<td>Column 1</td>
<td>Column 2</td>
</tr>
<tr>
<td></td>
<td>Column 1</td>
<td>Column 2</td>
</tr>
<tr>
<td></td>
<td>Column 1</td>
<td>Column 2</td>
</tr>
<tr>
<td></td>
<td>Column 1</td>
<td>Column 2</td>
</tr>
</tbody>
</table>

I'd suggest using the the CSS/Counter answer by #pravin-prajapati because it requires no JS overhead and will scale easily.
Was interested in what the problem was with your code because it looked fine to me so rebuilt it. Seemed to be working fine.
I'm guessing the problem is actually in the way you're attaching code to the .delete click, especially if you're adding new rows or recreating rows after an edit.
If you add new rows after the initial document.ready (or window.onload...) has attached the callback to the existing .delete elements, it will not automatically attach the callback to the new .delete elements.
In other words, don't do this in your init:
$('.delete').on('click', function(){
// do stuff
});
because that will only work for .delete elements that exist during the init. There are a few ways around this but an easy way is to listen for click events on a parent of the rows and then filter them to your actual target before running the callback. jQuery's on method makes this easy.
Below is an example with the table as the event listener.
EDIT:
If, for some reason, this isn't possible, you might look into using jQuery.clone() and setting withDataAndEvents and/or deepWithDataAndEvents to true like $('tr.template').clone(true, true);. This will copy the <tr> and any event handlers attached to it (first 'true') and any event handlers attached to any of its child elements (second 'true'). jQuery Clone Docs
$(document).ready(function(){
// your function, copied 100%
function setIndex(){
$("td.index").each(function(index) {
$(this).text(++index);
});
}
// set the index to begin with. Note the last three
// row indexes are actually empty in the sample HTML
setIndex();
// Move the click listener to the table.
$('table').on('click', '.delete', function(){
// remove the tr...
$(this).parents('tr').remove();
//... and reset the index
setIndex();
})
});
table {
font-family: sans-serif;
margin: 10px;
}
table td {
border: 1px solid #ccc;
padding: 10px;
}
.delete {
color: red;
cursor: pointer;
font-size: 80%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>Index</th>
<th>Name</th>
<th>Property</th>
<th>Edit/Delete</th>
</tr>
</thead>
<tbody>
<tr>
<td class="index">Index here</td>
<td>NameOne</td>
<td>PropOne</td>
<td><span class="edit">Edit</span> <span class="delete">Delete</span></td>
</tr>
<tr>
<td class="index">2</td>
<td>NameTwo</td>
<td>PropTwo</td>
<td><span class="edit">Edit</span> <span class="delete">Delete</span></td>
</tr>
<tr>
<td class="index">3</td>
<td>NameThree</td>
<td>PropThree</td>
<td><span class="edit">Edit</span> <span class="delete">Delete</span></td>
</tr>
<tr>
<td class="index"></td>
<td>Name 4</td>
<td>Prop 4</td>
<td><span class="edit">Edit</span> <span class="delete">Delete</span></td>
</tr>
<tr>
<td class="index"></td>
<td>Name 5</td>
<td>Prop 5</td>
<td><span class="edit">Edit</span> <span class="delete">Delete</span></td>
</tr>
<tr>
<td class="index"></td>
<td>Name 6</td>
<td>Prop 6</td>
<td><span class="edit">Edit</span> <span class="delete">Delete</span></td>
</tr>
</tbody>
</table>

EDIT
Praven Prajapati's answer surprised me.
I didn't know that very cool CSS feature.
Praven's answer really is better.
And if you need to refer to that number in a JS/jQuery code... And can't get it because it's a not in DOM pseudo-element... Then use .index() for that particular part of your code! Let CSS work on the rest.
jQuery way:
You need to refer to a row index... Use the .index() method.
Then on .delete click (I'm sure you can delete the row), just call a function to update the row index cell using that method.
Same after appending a new row...
Important
Use delegation with .on() on the classes present in your table rows, since you add new rows that are not present on page load code parsing. ;)
That is a Will's catch. (See his answer)
function updateRowCount(){
$("table tbody tr").each(function(){
$(this).find(".index").html($(this).index());
});
}
// Run on load
updateRowCount();
$(document).on("click",".delete",function(){ // Use delegation here!
$(this).parents("tr").remove();
updateRowCount();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>Index</th>
<th>Name</th>
<th>Property</th>
<th>Edit/Delete</th>
</tr>
</thead>
<tbody>
<tr>
<td class="index"></td>
<td>NameOne</td>
<td>PropOne</td>
<td><span class="edit">Edit Icon</span> <span class="delete">Delete Icon</span></td>
</tr>
<tr>
<td class="index"></td>
<td>NameTwo</td>
<td>PropTwo</td>
<td><span class="edit">Edit Icon</span> <span class="delete">Delete Icon</span></td>
</tr>
<tr>
<td class="index"></td>
<td>NameThree</td>
<td>PropThree</td>
<td><span class="edit">Edit Icon</span> <span class="delete">Delete Icon</span></td>
</tr>
</tbody>
</table>

Related

Getting value from another column when clicking targeted column JQuery

When the user clicks on the 'Number' column I want to be able to get the 'Name' column value in the same row. So for example if I clicked on '999' I would want to be able to get David.
$('#table').on('click', 'td:nth-child(2)', function()
{
row = $(this).text();
alert(row);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border id='table'>
<thead>
<td>Name</td>
<td>Number</td>
<td>Address</td>
</thead>
<tbody>
<tr>
<td>David</td>
<td>999</td>
<td>Street 1</td>
</tr>
<tr>
<td>Bob</td>
<td>555</td>
<td>Street 3</td>
</tr>
<tr>
<td>Jessica</td>
<td>068</td>
<td>Street 5</td>
</tr>
</tbody>
</table>
You can use $(this).closest('tr').find('td:first').text() to get the closest first td and its text.
If the wanted item is inside of the tr but you dont know the place or you want it dynamically, you can add a class or id to the name td and change the code to this $(this).closest('tr').find('#WantedRowId').text()
$('#table').on('click', 'td:nth-child(2)', function() {
alert($(this).closest('tr').find('td:first').text());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border id='table'>
<thead>
<td>Name</td>
<td>Number</td>
<td>Address</td>
</thead>
<tbody>
<tr>
<td>David</td>
<td>999</td>
<td>Street 1</td>
</tr>
<tr>
<td>Bob</td>
<td>555</td>
<td>Street 3</td>
</tr>
<tr>
<td>Jessica</td>
<td>068</td>
<td>Street 5</td>
</tr>
</tbody>
</table>
You can find below a more appropriate solution that dynamically checks what is the "Name" column index and retrieves accordingly.
As such, if you insert other columns, like ID and what not, it'll still work without updating this specific logic.
$('#table').on('click', 'td:nth-child(2)', function()
{
$td = $(this);
indexCol = $td.closest('table').find('td:contains(Name)').index()
alert( $td.closest('tr').find('td').eq(indexCol).text());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border id='table'>
<thead>
<td>Name</td>
<td>Number</td>
<td>Address</td>
</thead>
<tbody>
<tr>
<td>David</td>
<td>999</td>
<td>Street 1</td>
</tr>
<tr>
<td>Bob</td>
<td>555</td>
<td>Street 3</td>
</tr>
<tr>
<td>Jessica</td>
<td>068</td>
<td>Street 5</td>
</tr>
</tbody>
</table>

How to wrap a row of the table when a checkbox in it is selected?

I am working on a table in which I have to select a row when a check-box in that specific row is clicked. Only the row in which check-box is selected should be selected or lets say highlight it with red color. I have been trying to use a wrap function in JavaScript/jquery which is not showing any effect in my table. I had added the portion of code I was working. How do I do it?
Response.Write "<table><tr><td class='cell1'>Project</td><td class='cell1'>Project ID</td><td class='cell1'>Finish</td></tr>"
WHILE NOT rs.eof
Response.Write "<tr><td class='celld'>"& rs(projectname") &".</td>"
Response.Write "<td class='celld'>"& rs("productID") &"</td>"
Response.Write"<td class='celld'><input var='"& rs("productID") &"' type='checkbox' id='finish' checked></td></tr>"
rs.MoveNext
WEND
<script>
$("#finish").onclick(function(){
$(".celld").wrap(" <div style='color:red'/>");
});
</script>
You can toggle .highlight class on parent(ancestor) tr when checkbox inside change it's state:
$(document).ready(function(){
$("table input[type='checkbox']").on('change', function(){
$(this).closest('tr').toggleClass("highlight");
});
});
Css:
.highlight{
background-color:red;
}
Check the below snippet
$(document).ready(function() {
$("table input[type='checkbox']").on('change', function() {
$(this).closest('tr').toggleClass("highlight");
});
});
table {
border: 2px solid blue;
}
table td {
border: 1px solid green;
}
.highlight {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>Col 1</td>
<td>Col 2</td>
<td>Col 3</td>
<td>Col 4</td>
</tr>
<tr>
<td>Data 1</td>
<td>Data 2</td>
<td>Data 3</td>
<td>Select row
<input type="checkbox">
</td>
</tr>
<tr>
<td>Data 1</td>
<td>Data 2</td>
<td>Data 3</td>
<td>Select row
<input type="checkbox">
</td>
</tr>
<tr>
<td>Data 1</td>
<td>Data 2</td>
<td>Data 3</td>
<td>Select row
<input type="checkbox">
</td>
</tr>
</table>
I see you're using jQuery, so it's actually quite easy. Attach an on change listener to the checkbox, and whenever a change is triggered, select it's parent tr element and apply a class to it.
$('.checkbox').on('change', function() {
$(this).parents('tr').addClass('hightlight');
});
Note that you also need this class to be defined in your styles, for it to actually, visually change the row.
You have a couple of issues with your code. Firstly inside the loop you're creating multiple elements with the same id attribute, which is invalid. You should use a common class to select the elements. Also the input does not have var attribute, I presume this should be value.
From there you can attach a single event handler to all those elements which traverses the DOM to find the relevant tr. Note that the jQuery method to add a click event handler is click(), not onclick(). With checkboxes you should also hook to the change event to cater for those browsing via the keyboard. You can also set the class based on the state of the checked property of the checkbox using toggleClass().
Finally you cannot wrap a td in a div as this too is invalid. It would be better to simply add a class to the tr which sets the required CSS rules. Something like this:
<table cellpadding="2" width="100%" cellspacing="0" border="1">
<tr>
<td class="tdcell1">Project</td>
<td class="tdcell1">Project ID</td>
<td class="tdcell1">Finish</td>
</tr>
<tr>
<td class="tdcelld">Project Name #1.</td>
<td class="tdcelld">ProductId #1</td>
<td class="tdcelld">
<input value="ProductId1" type="checkbox" class="finish">
</td>
</tr>
<tr>
<td class="tdcelld">Project Name #2.</td>
<td class="tdcelld">ProductId #2</td>
<td class="tdcelld">
<input value="ProductId2" type="checkbox" class="finish">
</td>
</tr>
</table>
$(".finish").click(function(){
$(this).closest('tr').toggleClass('red', this.checked);
});
.red { color: red; }
Working example

How to copy specific content from one table to another using Javascript

I am currently developing a tool to display large amount of data in different tables. Different amount of data from one table has to be assigned into another table more than once. This view takes almost 20 seconds to load and i want to lower the time by manipulating the DOM instead of assigning every match within PHP. I want to place a few identifiers hidden in the first table and on click of one row, show the additional data within the next element.
Here is an example how the Tables look before:
<table>
<tr>
<th>Name</th>
</tr>
<tr class="iWantToClickThis">
<td>Bla Bla</td>
<td style="visibility:hidden;">3,5</td>
</tr>
</table>
<table style="visibility:hidden">
<tr>
<th>Additional Header</th>
</tr>
<tr id="1">
<td>Additional Info 1</td>
</tr>
<tr id="2">
<td>Additional Info 2</td>
</tr>
<tr id="3=>
<td>Additional Info 3</td>
</tr>
<tr id="4">
<td>Additional Info 4</td>
</tr>
<tr id="5">
<td>Additional Info 5</td>
</tr>
<tr id="6">
<td>Additional Info 6</td>
</tr>
</table>
And after the click:
<table>
<tr>
<th>Name</th>
</tr>
<tr class="iWantToClickThis">
<td>Bla Bla</td>
<td style="visibility:hidden;">3,4,5</td>
</tr>
<tr>
<td colspan="2>
<table>
<tr>
<th>Additional Header</th>
</tr>
<tr id="3">
<td>Additional Info 3</td>
</tr>
<tr id="5">
<td>Additional Info 5</td>
</tr>
</table>
</td>
</table>
I've found out how to achieve this with a single row but how do i do that with different, identitying them by their ids?

Break a HTML Table to two tables dynamically in javascript

I am using an user control in asp.net in which I am creating a html table from code behind. Initial structure is given below.
<table>
<tr>
<td>Property1</td>
<td>Property2</td>
<td>Property3</td>
<td>Property4</td>
</tr>
<tr>
<td>Value1</td>
<td>Value2</td>
<td>Value3</td>
<td>Value4</td>
</tr>
</table>
My problem is I want to restructure it according to the size of container it is going to be placed [as it is a user control]. For Ex If width of each cell is 20px and container width is 40px then structure will be as given below;
<table>
<tr>
<td>Property1</td>
<td>Property2</td>
</tr>
<tr>
<td>Value1</td>
<td>Value2</td>
</tr>
</table>
<table>
<tr>
<td>Property3</td>
<td>Property4</td>
</tr>
<tr>
<td>Value3</td>
<td>Value4</td>
</tr>
</table>
Thanks for the suggestion #user2167382.
Finally I have solved it though I had to use jquery.
Below is my html.
<table id="sourceT">
<tr>
<td>Col 1</td>
<td>Col 2</td>
<td>Col 3</td>
</tr>
<tr>
<td>Col 1 - value</td>
<td>Col 2 - value</td>
<td>Col 3 - value</td>
</tr>
</table>
<table id="targetT">
</table>
Here is the jquery logic.
var $target = $("#targetT");
$("#sourceT tr").each(function() {
var $tds = $(this).children(),
$row = $("<tr></tr>");
var i=1;
while(i<3)
{
alert(i) ; $row.append($tds.eq(i).clone()).appendTo($target);
i++;
}
});
Hope it will help somebody else.

How to append a table row towards last of a row with a specific class?

I'm trying to append a row to the html format of an asp data grid. My grid is having paging and that too is converted as a row in the html format. So, I added a class to the rows with the actual records. Now, i need to append an html table row to the grid. This should be appended towards the end of the records. Somebody knows how to do this?
Table Structure:
<table>
<th>
</th>
<tbody>
<tr class="clientData">1</tr>
<tr class="clientData">2</tr>
<tr class="clientData">3</tr>
<tr>Exclude This Row</tr>
<tr>Exclude This Row</tr>
</tbody>
</table>
Script:
{ $("#ctl00_Content_GrdCustomer tbody").append(selCustomersRow); } //
Something like
$('#ctl00_Content_GrdCustomer tbody tr.clientData').last().after(selCustomersRow);
Or like Angel's comment, select directly the last tr.clientData :
$('#ctl00_Content_GrdCustomer tbody tr.clientData:last').after(selCustomersRow);
http://api.jquery.com/after/
A better way would be to use the correct table tags.
i.e.
<table>
<thead>
<tr>
<td>Column header 1</td>
<td>Column header 2</td>
<td>Column header 3</td>
</tr>
</thead>
<tbody>
<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>
</tbody>
<tfoot>
<tr>
<td>Column footer 1</td>
<td>Column footer 2</td>
<td>Column footer 3</td>
</tr>
</tfoot>
</table>
You may not need to have a header, but you can stick all of your "records" within the tbody and your pagination within the tfoot.
This way you can use
$("#ctl00_Content_GrdCustomer tbody").append(selCustomersRow);
Which will append the row to the end tbody, but before the pagination within the tfoot.
Try that ...
{ $("#ctl00_Content_GrdCustomer tbody tr").last().append(selCustomersRow); }

Categories