Sorting a Multicolumn Table - Java Script

In practice,it’s very rare to have a single-column table,which is why the next task is to sort a table with more than one column.Suppose you added a second column to the table in the previous example, perhaps to display the first name of a person in addition to the last name:

Of course, the functions from the previous section only worked with one column, so modifications are needed.

The comparison function generator

Earlier,it was mentioned that functions are just like any other type in JavaScript, meaning that they can be passed as arguments to other functions or returned as a function value.You have already seen a function passed to another function (the sort() method); now it’s time to look at a function that returns a function.

The major limitation of the comparison function is its acceptance of two — and only two — arguments, meaning that additional information can’t be passed in.To get around this, you can create a comparison function generator,which is a separate function that returns a comparison function.

Because the compareTRs() must know which the column’s values to compare,it is necessary to pass in an additional argument: the index of the column to act on. Using a comparison function generator,it’s possible to pass this extra value into the comparison function:

The generateCompareTRs() function takes only one argument,which is the index of the column to acton.It returns as its function value another function that looks suspiciously like compareTRs().Note that the iCol argument,even though it isn’t defined within the comparison function,is used within the comparison function.You may recognize this as a closure .The variable iCol is captured by the comparison function and,therefore,can be used when it is returned by generateCompareTRs().

With the function defined, you can generate any comparison function necessary to sort a column:

The first line in the previous code generates the exact same compareTRs() function you first defined in the previous section.The second and third lines generate a comparison function that compares the second and third columns,respectively. Of course, you don’t need to assign the comparison function to a variable;it can just be passed directly into the sort() method:

aTRs.sort(generateCompareTRs(0));

In fact,this is how the sortTable() function must be modified to work with multiple columns.

Modifying the sortTable() function

Because there are multiple columns to deal with,the sortTable() function must now accept another argument indicating the index of the column to sort.Then, it can pass that value into the generateCompareTRs() function to sort the appropriate column:

With these two changes, it’s now possible to pass in which column to sort. Don’t forget, this change also needs to be included on the column headers in the table:

Of course, this function isn’t limited to tables with just two columns. Any table with any number of correct column index to the function.

Sorting in descending order

In the first two examples,you learned how to sort single column and multicolumn tables in ascending order. Now,it’s time to learn how to sort the table columns in descending order.

First and foremost, consider the expected behavior of a sortable table. When you sort a column in, say,Microsoft Outlook, you click on the column header. When you do this,the column is sorted in ascending order.If you then click on the column header a second time,the column sorts into descending order.This functionality is pretty standard in user interface design,so you really want to mimic it in your tables.

You can already sort each column in ascending order, so you’re halfway there.The crux of this problem is that,on the second click, you want to sort in descending order. This means that in order to sort in descending order, you must already have clicked on the column header once (so the column is already sorted in ascending order).You can simply reverse the order (using the reverse() method) of the column to sort in descending order.

To make this change, it’s necessary to once again modify the sortTable() function.

Modifying the sortTable() function

In order to create a descending sort, it is necessary to store the column index passed into the function for later reference. To do this, you can create an expandoproperty on the table.An expando property is an extra JavaScript property that is added to an object during runtime.The expando property in this example is called sortCol,and it simply stores the index of the column that was sorted last:

Next,code must be added to check whether the column index being passed in is the same as the last sorted column index.If they are equal,the array should just be reversed instead of sorted:

The best thing about this change is that it doesn’t require any changes in the HTML. So now when the user clicks a column header once, it sorts into ascending order as always. When the user clicks the column header a second time,it is sorted in descending order.If the user clicks it a third time,the order reverses once again, sorting in ascending order. But so far this only works with strings. What about other data types?

Sorting with different data types

Although sorting strings is a good start, many times you may want to sort a column that contains other data types. Because the DOM text nodes always contain string values, that means the data must be converted before any sorting can be done. To do this, it’s necessary to create a conversion function.

Creating a conversion function

A conversion function is relatively simple: You need two arguments,one for the value to be converted and one indicating what type of conversion should take place.Generally speaking, three conversions are frequently used: convert to integer, convert to float, and convert to date. Of course,if you need a string, no conversion is necessary.

For this conversion function, the second argument is a string indicating the type of conversion to do:

  • “int” to convert to an integer
  • “float” to convert to a float
  • “date” to convert to a date
  • Any other value always returns a string

Here’s the function:

This function uses the switch statement to determine the value of sDataType(remember, the switch statement works on all types in JavaScript). When sDataType is “int”, parseInt() is called on sValue and the result is returned; when sDataType is “float”, parseFloat() is called and the result is returned. If sDataType is “date”,then Date.parse() is used in conjunction with the Date constructor to create and return a new Date object.If sDataType is any other value, the function returns sValue.toString(),to ensure that a string value is returned. This means that if sDataType is “string”, null, or any other value, convert() always returns a string. For example:

In this example, convert() is used to convert the string “25” into an integer, meaning that when typeof is called against it,the value returned is “number”. If, however, the second argument is“string”, the returned value is a string and typeof returns “string”.A string is also returned when the second argument is omitted and when the second argument is “football”.

With the conversion function complete, you must modify the rest of the code to use it.

Modifying the code

The first step is to modify the generateCompareTRs() function, which now must accept an additional argument indicating the data type to use when comparing values.Then, the values from the table must be converted into the appropriate data type within the comparison function:

This change to generateCompareTRs() once again takes advantage of JavaScript’s support of closures,passing the sDataType argument directly into the comparison function.Unfortunately, you can no longer use the localeCompare() method to return the appropriate function value because numbers and dates don’t support it. Because you can’t be sure which type of value is being stored, and it doesn’t make sense to handle each data type’s comparisons differently, it’s best just to use less-than and greaterthan to determine which value to return:

Using this methodology, the comparison function returns the correct value no matter which data type is being used.

Next,you modify the sortTable() function to use the new comparison function this function also must accept an additional argument indicating the data type to use for the comparison.Then, this data type must be passed into the generateCompareTRs() function.

With the JavaScript code all done, it’s time to add extra data to the table for the various data types:

Note that the code in the column headers has also been updated to include the new data type argument. For the first two columns,you don’t have to change the function call because both columns contain strings.The third and fourth columns, however, contain dates and integers,respectively. For each of these column headers, you must include the data type argument.

Advanced sorting

At this point,you’ve already learned how to sort different data types in the same table in both ascending and descending order. Unfortunately, it’s very rare that a table contains only regular data types.The truth is that you will always end up with links,images,or some other sort of HTML in tables; and users will still want to sort. The most common situation is probably a column that contains icons.Whether the icon is indicative of something (for instance, an attachment on an e-mail) or just decorative,people want to be able to sort by it.The previous code does not support such a thing, but that can be fixed.

The concept

Keep in mind is that each cell in a table must have a sortable value, meaning a value that is a string, integer, float, or date. Because all HTML code can’t be converted directly into one of these data types, you need to specify an alternate value to sort by. This can be accomplished by adding an extra attribute on each <td/> that contains HTML, like this:

<td value=”blue”><img src=”blueimage.gif” /></td>

Because this table cell contains an image, you normally wouldn’t be able to sort it. However, the addition of the value attribute specifies that the value to sort is “blue”, not the contents of the <td/> element.

And as you learned earlier, it is possible to access this new attribute using the DOM getAttribute() method:

var sValue = oTD.getAttribute(“value”);

Now,it isn’t necessary to add a value attribute to every cell in a table, because this gives you a lot of redundant information.You should only add the attribute to those table cells containing HTML code.

For example,the following table lists filenames along with their associated icons.Note that only the first column uses the extra value attribute:

However,this new attribute alone doesn’t solve the problem.You must also update the JavaScript code to take advantage of the value attribute.

Modifying the code

This final modification to the code determines whether to get the sortable value from the <td/> element’s text or from the value attribute. Here’s the updated code:

Basically, vValue1 and vValue2 are defined to have no initial value. Then, you the first row has a value attribute defined by using getAttribute(), which will return null when the attribute doesn’t exist. When placed in the if statement, null is evaluated as false and a non-null value is evaluated as true. Therefore,if the value attribute exists, both vValue1 and vValue2 are assigned the value of the attribute for oTR1 and oTR2, respectively. If the value attribute doesn’t exist, then vValue1 and vValue2 are assigned the value contained inside the table cell.

The only thing left to do is to add the sorting calls to the HTML code:

This HTML code sorts both columns by using strings; therefore,the third argument isn’t necessary when calling sortTable().Even though the first column contains images,the code uses the value attribute to sort it in both ascending and descending order.


All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

Java Script Topics