-->

## Table Sort

See the demo page for the finished version of the code.

#### Team Rankings

The "Rank" column basically shows how each team ranks in the category signified by the column just sorted. For example, when the offensive statistics table is sorted by total yards, the team with the most yards gained will be ranked first, the team with the second most yards gained will be ranked second and so on.

The easiest way to do this is to just number the rows from top to bottom starting with #1. Of course, if the user reverses the sort direction of that column, the team ranked #1 will be at the bottom of the table.

So the function first has to determine which way to go, from top to bottom or bottom to top.

```function setRanks(tblEl, col, rev) {

// Determine whether to start at the top row of the table and go down or
// at the bottom row and work up. This is based on the current sort
// direction of the column and its reversed flag.

var i    = 0;
var incr = 1;
if (tblEl.reverseSort[col])
rev = !rev;
if (rev) {
incr = -1;
i = tblEl.rows.length - 1;
}
```

It does this by looking at the current sort direction as well as the initial sort direction. All the columns were set up to initially sort from best to worst, so that value is passed on from `sortTable()` along with the table body element and the index of the column just sorted. This allows the function to determine whether the best team in that category is currently at the top or the bottom of the table.

Next, it simply loops through each row, going in that direction and assigning each a rank in order: 1, 2, 3, etc. The rank is not displayed in the table just yet, we just want to number each row at this point.

What complicates matters is that teams can be tied in rank. For example, both Chicago and Tampa Bay had 4,694 yards of total offense. So they tie for 26th place. Washington comes next with 4,435, making it 28th (not 27th, because there were 27 teams with more yards, so they rank 28th). That's the convention used for these particular statistics.

So, even though Tampa Bay is in the 27th row, it should have a rank of 26. Washington is in the 28th row and has a rank of 28.

To accomplish this, the code starts a count at 1 and goes through each row, starting at either the top or bottom as determined earlier and bumping the count up by one for each.

```  // Now go through each row in that direction and assign it a rank by
// counting 1, 2, 3...

var count   = 1;
var rank    = count;
var curVal;
var lastVal = null;

// Note that this loop is skipped if the table was sorted on the
// name column.
while (col > 1 && i >= 0 && i < tblEl.rows.length) {

// Get the value of the sort column in this row.
curVal = getTextValue(tblEl.rows[i].cells[col]);

// On rows after the first, compare the sort value of this row to
// the previous one. If they differ, update the rank to match the
// current row count. (If they are the same, this row will get the
// same rank as the previous one.)
if (lastVal != null && compareValues(curVal, lastVal) != 0)
rank = count;
// Set the rank for this row.
tblEl.rows[i].rank = rank;

// Save the sort value of the current row for the next time
// around and bump the row counter and index.
lastVal = curVal;
count++;
i += incr;
}
```

If the team in a given row tied with the team in the previous row (using the column sorted on), it gets the same rank as the previous team. Otherwise, it's rank is set equal to the current count.

Note that if the table was sorted on the team name column, this proccess can be skipped as rank does not apply.

When finished, the row element for each team will have it's proper ranking stored in a user defined property called `rank.` The final step is to display these ranks in the first column of the table.

```  // Now go through each row (from top to bottom) and display its rank.
// Note that when two or more rows are tied, the rank is shown on the
// first of those rows only.

var rowEl, cellEl;
var lastRank = 0;

// Go through the rows from top to bottom.
for (i = 0; i < tblEl.rows.length; i++) {
rowEl = tblEl.rows[i];
cellEl = rowEl.cells[0];
// Delete anything currently in the rank column.
while (cellEl.lastChild != null)
cellEl.removeChild(cellEl.lastChild);
// If this row's rank is different from the previous one, Insert a
// new text node with that rank.
if (col > 1 && rowEl.rank != lastRank) {
cellEl.appendChild(document.createTextNode(rowEl.rank));
lastRank = rowEl.rank;
}
}
```

The above code does just that. This time it always starts with the top row and works down, updating the first column of each row.

To alter the text in the table cell, it first deletes any content currently in the cell by repeatedly calling `removeChild()` until the cell has no more child nodes. Then it creates a new text node using the row's rank and adds it to the cell node via `appendChild().`

In the cases where teams are tied in rank, the rank is displayed only in the first (topmost) row. Again, this is just for aesthetic purposes. Also note that if the table was sorted on the team name column, the rank column is simply left empty.

### Conclusion

By making use of DOM features to dynamically sort tables on the browser, you can eliminate the need for CGI or other server-side code that does the same thing. This can not only reduced the load on your web server, but possibly other resources, like a back-end database.

It also means less waiting for your users as their browsers won't have to make repeated requests to the server just to rearrange data they already have.