Reputation: 26317
I have some data in a table that looks like this:
Adam $50
Evan $20
Frank $80
Harold $90
Jeff $20
Linus $10
Sam $87
Zach $100
Results are sorted by name alphabetically and can have any amount of $ beside them.
I need to make the top five amounts bold and red as well as append a #1, #2, #3 etc beside the first five names.
Can jQuery do this without sorting by the $ column?
Upvotes: 0
Views: 225
Reputation: 53576
Not directly, this is too concrete to be handled by an abstract framework layer. However, you can accomplish this fairly easily. For a table like :
<table id="table_id">
<tr><th class="rank"></th><th class="name">Name</th><th class="amount">Amount</th></tr>
<tr><td></td><td>Adam</td><td>$50</td></tr>
<tr><td></td><td>Evan</td><td>$20</td></tr>
<tr><td></td><td>Frank</td><td>$80</td></tr>
<tr><td></td><td>Harold</td><td>$90</td></tr>
<tr><td></td><td>Jeff</td><td>$20</td></tr>
<tr><td></td><td>Linus</td><td>$10</td></tr>
<tr><td></td><td>Sam</td><td>$87</td></tr>
<tr><td></td><td>Zach</td><td>$100</td></tr>
</table>
You can do :
var top = 5; // apply only transformation to the top n rows
var rankCol, nameCol, amountCol;
$('#table_id').find('tr')
// get first row and find where are the name and amount columns...
.slice(0, 1).each(function(i,row) {
rankCol = $(row).find('.rank').index();
nameCol = $(row).find('.name').index();
amountCol = $(row).find('.amount').index();
}).end()
// remove first row
.slice(1)
// sort returned set by 'amount' in ascending order
.sort(function(a,b) {
return parseFloat($(a).find('td:eq('+amountCol+')').text().substr(1)) - parseFloat($(b).find('td:eq('+amountCol+')').text().substr(1));
})
// get the last 'top' rows
.slice(-top)
// apply bold + red to column 'amount'
.find('td:eq('+amountCol+')').css({'font-weight':'bold', 'color':'red'}).end()
// prepend #n to column 'rank'
.find('td:eq('+rankCol+')').each(function(i,col) {
$(col).text('#'+(top-i)+'. ');
})
;
The code was organized for readability, but also so you can see how JQuery can apply a reusable pattern to chain up the calls on your results. If your table layout is different, for example you have 5 columns and "amount" is in the 5th, then the code will still work without modification, all you need is to set some class name to your "name" and "amount" columns and look for that class in the first row.
** EDIT ** I also added a reserved column to put the rank's text. This render nameCol
obsolete, but I kept it in the code anyway. Having such a reserved column aligns everything beautifully. :) The number of top rows are now variable based. ... I could still play with the code to make it even more flexible / reusable, but I think you get the point.
** NOTE ** you could replace the css()
call with addClass()
instead that will define bold + red. You could even replace the prepend(string)
call with a prepend(element)
instead so you can actually style the "#n" before the name.
Upvotes: 1
Reputation: 23943
Here's another approach.
var arr = $('#mytable').find('td:last-child')
.map( function(){
var cleanval = parseInt( $(this).text().replace('$',''),10 );
$(this).addClass('s_'+cleanval);
return cleanval;
})
.get()
.sort( function(a,b){ return (b-a); } )
.slice(4);
for( var i=0,j=arr.length;i<j;i++ ) {
$('td.s_'+arr[i]).addClass('colorize');
}
Here's a working fiddle.
Upvotes: 0
Reputation: 359956
$(function ()
{
var i = 5,
values = $('#myTable').find('td:odd').map(function (i, elt)
{
var $elt = $(elt);
return {$td: $elt,
value: parseFloat($elt.text().slice(1))};
}).get().sort(function (a,b)
{
return b.value-a.value;
});
while(i--)
{
values[i].$td.css({fontWeight: 'bold', color: '#F00'})
.prev().append(' #' + (i+1));
}
});
Functioning demo: http://jsbin.com/iseme3/7
Feel free to ask about anything in there you don't understand.
Upvotes: 4