Thang Pham - 2 years ago 178
HTML Question

jQuery sortColumns plugin: How to sort correctly with rowspan

Following this post jQuery table sort (github link: https://github.com/padolsey/jQuery-Plugins/blob/master/sortElements/jquery.sortElements.js), I am successfully sort columns, however it does not work in the case of rowspan: For example, case like this

`````` Grape      3,096,671M
1,642,721M
Apple      2,602,750M
3,122,020M
``````

When I click on the second column, it try to sort

`````` Apple      2,602,750M
1,642,721M
Grape      3,096,671M
3,122,020M
``````

(Expected result should be that it should only sort within each rowspan

`````` Grape      1,642,721M
3,096,671M
Apple      2,602,750M
3,122,020M
``````

or

`````` Grape      3,096,671M
1,642,721M
Apple      3,122,020M
2,602,750M
``````

)

so either
which as you can see is not correct, please any jQuery guru help me fix this problem. Here is my code

``````var inverse = false;
function sortColumn(index){
index = index + 1;
var table = jQuery('#resultsTable');
table.find('td').filter(function(){
return jQuery(this).index() == index;
}).sortElements(function(a, b){
a = convertToNum(\$(a).text());
b = convertToNum(\$(b).text());

return (
isNaN(a) || isNaN(b) ?
a > b : +a > +b
) ?
inverse ? -1 : 1 :
inverse ? 1 : -1;
},function(){
return this.parentNode;
});
inverse = !inverse;
}
function convertToNum(str){
if(isNaN(str)){
var holder = "";
for(i=0; i<str.length; i++){
if(!isNaN(str.charAt(i))){
holder += str.charAt(i);
}
}
return holder;
}else{
return str;
}
}
``````

Question:

1.How do I sort this with rowspan. THE NUMBER OF ROWSPAN IS NOT ALWAYS THE SAME. The above example both Grape and Apple have rowspan of 2, but this is not always the case.

2.Can any explain this syntax:

`````` return (
isNaN(a) || isNaN(b) ?
a > b : +a > +b
) ?
inverse ? -1 : 1 :
inverse ? 1 : -1;
``````

So I can see that if either a or b is not a number, then do string comparison otherwise do number comparison, but I dont understand the

``````inverse ? -1 : 1 :
inverse ? 1 : -1;
``````

Test cases

``````<table id="resultsTable">
<tr>
<th>Fruit</th>
<th onclick="sortColumn(1)">Quantity</th>
<th onclick="sortColumn(2)">Rate</th>
</tr>
<tbody>
<tr>
<td rowspan="4">Grape</td>
<td>15</td>
<td>5</td>
</tr>
<tr>
<td>4</td>
<td>2</td>
</tr>
<tr>
<td>88</td>
<td>1</td>
</tr>
<tr>
<td>11</td>
<td>3</td>
</tr>
<tr>
<td rowspan="3">Melon</td>
<td>21</td>
<td>2</td>
</tr>
<tr>
<td>2</td>
<td>0</td>
</tr>
<tr>
<td>35</td>
<td>1</td>
</tr>
<tr>
<td rowspan="6">Melon</td>
<td>24</td>
<td>5</td>
</tr>
<tr>
<td>66</td>
<td>2</td>
</tr>
<tr>
<td>100</td>
<td>4</td>
</tr>
<tr>
<td>21</td>
<td>1</td>
</tr>
<tr>
<td>65</td>
<td>3</td>
</tr>
<tr>
<td>2</td>
<td>0</td>
</tr>
</tbody>
<table>
``````

Conditions for the code to work:

• Columns containing `td`s with `rowspan` must all be on the left of the table
• All the `td`s in these columns must have a `rowspan`, even if it's 1
• The groups of rows to sort are made with the rightmost of these columns (but it can easily be changed)

jsFiddle: http://jsfiddle.net/5GrAC/77/

``````var inverse = false;

function sortColumn(index) {
var trs = \$('#resultsTable > tbody > tr'),
nbRowspans = trs.first().children('[rowspan]').length,
offset = trs.first().children('[rowspan]').last().offset().left;

var tds = trs.children('[rowspan]').each(function() {
\$(this).data('row', \$(this).parent().index());
\$(this).data('column', \$(this).index());
\$(this).data('offset', \$(this).offset().left)
}).each(function() {
if(\$(this).data('offset') != offset)
return;

var rowMin = \$(this).data('row'),
rowMax = rowMin + parseInt(\$(this).attr('rowspan'));

trs.slice(rowMin, rowMax).children().filter(function() {
return \$(this).index() == index + \$(this).parent().children('[rowspan]').length - nbRowspans;
}).sortElements(function(a, b) {
a = convertToNum(\$(a).text());
b = convertToNum(\$(b).text());

return (
isNaN(a) || isNaN(b) ?
a > b : +a > +b
) ?
inverse ? -1 : 1 :
inverse ? 1 : -1;
}, function() {
return this.parentNode;
});
});

var trs = \$('#resultsTable > tbody > tr');
tds.each(function() {
if(\$(this).parent().index() != \$(this).data('row'))
\$(this).insertBefore(trs.eq(\$(this).data('row')).children().eq(\$(this).data('column')));
});

inverse = !inverse;
}
``````

Quick explanations:

• Finding all `td`s with `rowspan`
• Positions of these `td`s are saved, including left offset
• These `td`s are filtered by their original `offset` to work only with the rightmost ones
• `tr`s related to each kept `td` are sorted using the wanted column
• All `td`s with `rowspan` are finally moved back to their original position if necessary

About question 2, I will only complete bartlaarhoven's answer by saying, the code can also be written like the following:

``````return (
(isNaN(a) || isNaN(b) ? a > b : +a > +b) ? 1 : -1
) * (inverse ? -1 : 1);
``````

You can easily read that `inverse` is used to inverse the result.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download