HTML Tables can be pretty boring to look at! Although you can add a dash of CSS and beautify them, users demand more interactivity by representing and manipulating tables, at runtime.
Some common manipulation tasks performed with tabular data is adding and deleting rows, sorting and paginating data. JavaScript is the obvious choice to achieve these operations, but many lines of code need to be written in plain JavaScript, to traverse and manipulate the DOM tree. DOM operations can get tricky at times. To add to our woes, writing code that works cross-browser is tedious, especially when performing advanced manipulations. This is where a JavaScript library like jQuery comes in handy.
jQuery makes DOM operations less scary. It provides an abstraction layer and allows you to work with the DOM, without having to know every little thing about it. One of the biggest benefits of using jQuery is that it handles a lot of cross-browser issues for you.
In this article, I will share some jQuery techniques to manipulate Table Data. I will also share performance tips about jQuery selectors, caching selectors, and writing terse, efficient code. By using these tips, your code will be more effective. I am assuming you have a little experience working with jQuery. If not, Learning jQuery is a good place to start with
This article is based on my upcoming jQuery Book The Absolutely Awesome jQuery CookBook where I share similar self-contained recipes that you can easily incorporate in your websites or projects.
Defining the Table Structure
The first step to write effective jQuery is to write well-formed HTML. Here’s a subset of a well-defined HTML Table markup:
Observe how we have declared , , and tags in your table. We have also declared Id's and Classes where required, to allow jQuery selectors to have direct access to the DOM elements.
With a dash of CSS, our sample table looks like the following:
Tip 1: Insert a New Row as the Last Row of a Table
With the table in place, write the following code to insert a new row as the last row of the table
$(function () {
newRow = "" +
"E333 | " +
"Fujita | " +
"Makoto | " +
"fujita@devcurry.com | " +
"52 | " +
"
";
$('#someTable > tbody > tr:last').after(newRow);
});
When the page is rendered, you should see the newly added row.
We are using the jQuery selector extension :last to select the last matched row in our table. The after() method inserts the new row after the set of matched elements; in our case, after the last row.
Note: The above example works well for smaller tables, however in a large table, using the :last selector may not give you the best performance. As per the jQuery documentation, :last is a jQuery extension and not part of the CSS specs and hence cannot take advantage of the powerful native DOM methods that can parse any CSS selector, like querySelectorAll.
To achieve better performance, we can rewrite our code as:
$('#someTable > tbody > tr').filter(":last").after(newRow);
The code first selects rows using a pure CSS selector #someTable > tbody > tr and then uses filter(":last") to match the last row of the table.
Note: There are multiple ways in jQuery to achieve a certain requirement. A point to always remember is that jQuery will always use a native method (in our case we discussed querySelectorAll) if available, as it’s much quicker at getting elements and gives a notable performance with complex and large sets of data. jsperf.com is your friend to run tests when you are in doubt of which selectors or methods to use in your code, for the browsers you are supporting.
Tip 2: Insert a New Row in a Table at a Certain Position
Now let’s say you want to insert a new row as the 2nd row in a table. Use the following code:
var index = 2;
newRow = "" +
"E333 | " +
"Fujita | " +
"Makoto | " +
"fujita@devcurry.com | " +
"52 | " +
"
";
$('#someTable > tbody > tr').eq(index-1).before(newRow);
Refresh the page and you will see the new row gets added as the 2nd row.
Since indexes are zero based and we are passing index=2, .eq(index) would mean .eq(2) i.e. the 3rd row. So to add this to the 2nd row of a table, you first need to do index-1 and then you need to go back to the 2nd row of the table and insert .before() that, so that this new row now becomes the 2nd row of the table.
Alternatively to insert a row as the 2nd row in a table, you can also do
$('#someTable > tbody > tr:first').after(newRow);
which uses the :first selector to match the first row and insert a row after() it.
Here again just like we saw earlier for the last selector, for large tables, you will get performance benefits by using the filter :first.
Similarly you can also explore other child filter selectors like first-child, nth-child and so on from the jQuery documentation at api.jquery.com/category/selectors/child-filter-selectors/
To become a better developer, I cannot emphasize the fact enough that you should take out some time and go through the jQuery documentation. It’s probably one of the most well written documentation of any JavaScript library out there and getting familiar with difference selectors and API’s, will save you tons of time and frustration in a project.
Tip 3: Remove all Rows Except Header
If your table is well defined and contains a
, this piece of code will work to remove all the rows, except the header row
$('#someTable tbody tr').remove();
This code uses the remove() method to remove a set of rows inside tbody. Since we haven’t supplied the remove() method with any selector as a parameter, the above code removes all rows, as well as all elements, events and data in the rows.
If you want to remove all rows without removing data and events, use detach() instead of remove()
In case you do not have a defined and want to remove all rows except the first one (assuming first row is meant to be a header), use this code
$('#someTable tr:gt(0)').remove();
where the selector gt(0) selects all rows at an index greater than zero, within the matched rows. Similarly if you want to keep the first two rows and remove all others, change the above code to this
$('#someTable tr:gt(1)').remove();
Note: The jQuery documentation says “Because :gt() is a jQuery extension and not part of the CSS specification, queries using :gt() cannot take advantage of the performance boost provided by the native DOM querySelectorAll() method. For better performance in modern browsers, use $("your-pure-css-selector").slice(index) instead”
As seen and discussed earlier, in our case, a pure css selector would be $('#someTable tr'). All you need to do is use it with slice() to remove all except the first row.
$('#someTable tr').slice(1).remove();
Slice() is zero based and takes two arguments, start and end. Since we are supplying 1 as the first parameter to slice(), the above statement will return a new jQuery object that selects from the first row, to the end. Calling remove() removes this set of matched element returned by slice and you are left with only the first row.
Tip 4: Dynamically Add Thousands of New rows to a Table with Performance
jQuery gives us great power when it comes to manipulating the DOM, and with Great power, comes Great responsibility! Think about some of these functions that you can perform very easily using jQuery
- hide/delete/insert/update elements
- resize elements/change dimensions
- move/animate elements
and so on..
All these cause what is known as a reflow operation in the browser. Google Developers documentation defines reflow as “Reflow is the name of the web browser process for re-calculating the positions and geometries of elements in the document, for the purpose of re-rendering part or all of the document”.
Reflows can be very expensive if not done correctly.
Note: If you plan on becoming a serious front end engineer, I would advise you to spend some time reading about reflow and repaint operations.
To understand this better, let’s take an example where we have to dynamically insert 1000’s of rows in a table. We will make use of $.append() to add 5000 rows using two approaches. In the first approach, we will append new rows to the table, every time the loop iterates. In the second approach, we will construct a string with the new rows and then append the string only once after the loop is completed. We will then compare the two approaches and derive our conclusion as to which one of them is better and why.
To iterate the loop, I will be using the for loop rather than $.each.
Although a comparison of for vs $.each and performance vs readability is beyond the scope of this article, in my jQuery Book, I have included a chapter on using jsperf and demonstrated how for a large table, using our old for loop outperforms $.each.
To keep it simple for this article, let’s proceed with the for loop to perform iterations.
Use this piece code. I have declared some additional variables like t1, t2, t1t2 to measure the time differences while using the two approaches.
$(function () {
var $tbl = $("#someTable");
// Approach 1: Using $.append() inside loop
var t1 = new Date().getTime();
for(i=0; i < 5000; i++){
rows = "" + i + " | FName | LName |
";
$tbl.append(rows);
}
var t2 = new Date().getTime();
var t1t2 = t2-t1;
$('#result').append("Approach 1: Append Inside Loop took " + t1t2 + " milliseconds" + "");
// Approach 2: Using $.append() outside loop
var newrows;
var t3 = new Date().getTime();
for(i=0; i < 5000; i++){
newrows += "" + i + " | FName | LName |
";
}
$tbl.append(newrows);
var t4 = new Date().getTime();
var t3t4 = t4 - t3;
$('#result').append("Approach 2: Append Once Outside Loop " + t3t4 + " milliseconds" + "");
});
As discussed, we have two sets of code. Approach 1 calls $.append on each iteration of the loop whereas Approach 2 constructs a string (using +=) with the new rows and calls $.append only once after the loop iteration.
The difference is considerable, especially on IE and Safari.
Our example took just 2 columns and some fixed length data. Imagine in a real world scenario, where there are multiple columns, with variable data; the results would be dramatic.
In Approach 1, every time you are adding a new row to the table inside the loop, you are causing a reflow and the entire page geometry gets calculated every time with the new DOM change. In Approach 2, theoretically speaking, the reflow occurs only once, since the rows are constructed and added outside the loop. That’s why it’s very important for a front-end engineer to understand and evaluate the difference between the two approaches. Jsperf.com is your friend and use it whenever you can.
Off topic, in Approach 2, you could squeeze additional performance by not concatenating the string, but rather adding it as individual elements of an array and then use join outside the loop to construct the entire string in one go. If you know the length of the array beforehand, that will help too. Check this link to learn more about the same.
So these were some performance tips while working with HTML Tables. If you liked them, do check out my upcoming jQuery Book which is full of recipes demonstrating how to use jQuery to the best of its ability.
Download the entire source code from our GitHub Repository at bit.ly/dncm9-jqperf
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Suprotim Agarwal, MCSD, MCAD, MCDBA, MCSE, is the founder of
DotNetCurry,
DNC Magazine for Developers,
SQLServerCurry and
DevCurry. He has also authored a couple of books
51 Recipes using jQuery with ASP.NET Controls and
The Absolutely Awesome jQuery CookBook.
Suprotim has received the prestigious Microsoft MVP award for Sixteen consecutive years. In a professional capacity, he is the CEO of A2Z Knowledge Visuals Pvt Ltd, a digital group that offers Digital Marketing and Branding services to businesses, both in a start-up and enterprise environment.
Get in touch with him on Twitter @suprotimagarwal or at LinkedIn
Comment posted by
srinivas dandamudi
on Wednesday, December 18, 2013 2:42 AM
|
|
Hi Suprotim, Actually we are using 1st approach in our project. we are getting performance issues. This is very helpful to us. Thanks for the article.
|
Comment posted by
srinivas dandamudi
on Wednesday, December 18, 2013 4:28 AM
|
|
Hi Suprotim, Actually we are using 1st approach in our project. we are getting performance issues. This is very helpful to us. Thanks for the article.
|
Comment posted by
grgfrgr
on Tuesday, April 1, 2014 6:29 AM
|
|
ghfdgfdgfdgfdg
|
Comment posted by
Felix
on Friday, May 30, 2014 12:05 AM
|
|
Such a nice article. Thanks
|
Comment posted by
Olu
on Friday, November 21, 2014 6:42 AM
|
|
Very helpful article, thanks for this.
|
Comment posted by
Everardo T Cunha
on Tuesday, March 10, 2015 7:04 AM
|
|
Great article. I just bought your second book; well written and very practical.
How do i allow the user to edit table rows? Do you have any examples?
Thanks,
Everardo
|
Comment posted by
Suprotim Agarwal
on Thursday, March 12, 2015 5:52 AM
|
|
@Everardo Thank you. I appreciate the feedback and am glad you are enjoying reading the book.
For CRUD operations on Tables, get some ideas over here http://www.dotnetcurry.com/showarticle.aspx?ID=1006
|
|
Categories
JOIN OUR COMMUNITY
POPULAR ARTICLES
Tags
JQUERY COOKBOOK