20
Aug
2009

A couple of days ago, we used jQuery to automatically highlight any table rows where the value of a specified <td> was less than $100.

Yesterday, we used a different method (traversing the DOM) to highlight any table rows where the value of the "Sale Price" was 50% or more off of the value of the "Regular Price".

Today, we're going to combine both into one application. Both of the original methods will work the same. The only thing we're going to add is a clearRows() method, which will run before either of the two methods described above. This will remove the background color from all table rows, effectively "resetting" the table before either of the two highlight methods run.

Given the table below, allow the user to see which items are under $100, -or- which items are reduced by 50% or more.

<table id="inventoryTable" cellpadding="3" cellspacing="0">
<thead>
<tr>
	<td>Original Price</td>
	<td>Sale Price</td>
	<td>Description</td>
</tr>
</thead>
<tbody>
<tr>
	<td class="originalPrice">100.00</td>
	<td class="salePrice">65.00</td>
	<td>Green widget (Yellow stripes)</td>
</tr>
<tr>
	<td class="originalPrice">200.00</td>
	<td class="salePrice">110.00</td>
	<td>Lavender Widget (White dots)</td>
</tr>
<tr>
	<td class="originalPrice">200.00</td>
	<td class="salePrice">74.00</td>
	<td>Red Widget (Solid)</td>
</tr>
</tbody>
</table>

We're going to add 3 buttons to our markup. One for each of the two methods we want, and we're also going to add a "Clear" button to reset the table row background colors:

<div id="buttons">
	<input type="button" value="Items Under $100" id="cheapstuff" />
	<input type="button" value="Items 50% off" id="halfoff" />
	<input type="button" value="Clear" id="clearColors" />
</div>

Combining the two existing jQuery methods (from the previous two entries), our script would look like this:

$(document).ready(function() {

	$('#cheapstuff').click(function() {
		$('.salePrice').each(function() {
			if ($(this).text() < 100)
			$(this).parent().css('backgroundColor', '#EFEF00');
		});
	});

	$('#halfoff').click(function() {
		$('#inventoryTable tbody tr').each(function() {
			var reg  = $(this).children(':eq(0)').text();
			var sale = $(this).children(':eq(1)').text();

			if (reg/sale > 2)
				$(this).css('backgroundColor', '#EFEF00');
		});
	});

});

Now, we're going to add a method called clearRows(), which is going to loop over each <tr> in the table, and remove the background-color value:

function clearRows() {
	$('#inventoryTable tbody tr').each(function() {
		$(this).css('backgroundColor', '');
	});
}

As with the halfOff function, we use a selector to first find the element with id "inventoryTable", then traverse to that elements tbody, and finally to each tr element within.

Looping over that collection via jQuery's each() method, we set the css property 'backgroundColor' to an empty string. This effectively removes any existing background color from the element

Now that we have this clearRows() method, we have to put it to use. First, let's assign it as a handler for the "Clear" button's click event. The button has an id="clearColors" attribute, so our jQuery looks like this:

$('#clearColors').click(function() {
	clearRows();
});

You might be wondering why need a separate function for clearRows(). Why not just take the code that's in the clearRows() function and put it in the click handler for the $('#clearColors') element? If you're wondering that, good on ya.

We're actually going to reuse that code in a couple of places. If we only cleared the colors upon clicking the "Clear" button, what happens when a user clicks the "Items Under $100" button, and then clicks the "Items 50% off" button? They'll end up seeing a combination of both, which is not what we want. So, before either of the other two buttons are clicked, we want to call the clearRows() method. We can do that by adding a line of code to each of our existing click handlers:

$('#cheapstuff').click(function() {
	clearRows();
	$('.salePrice').each(function() {
		if ($(this).text() < 100)
		$(this).parent().css('backgroundColor', '#EFEF00');
	});
});

$('#halfoff').click(function() {
	clearRows();
	$('#inventoryTable tbody tr').each(function() {
		var reg  = $(this).children(':eq(0)').text();
		var sale = $(this).children(':eq(1)').text();

		if (reg/sale > 2)
			$(this).css('backgroundColor', '#EFEF00');
	});
});

Notice that now, the first line of each of these handler methods calls the clearRows() method, and then highlights only the appropriate rows.

We're going to make one final change before wrapping this up (and moving on to something different next time). If the "Clear" button has been clicked... if there are no table rows displaying a background color, we really don't need to display the "Clear" button. It's confusing to the user, as there's nothing to clear. So we're going to add a CSS declaration to set its "display" value to "none" on intial page load:

<style type="text/css">
	#inventoryTable			{ margin:0 0 12px 0; }
	#inventoryTable thead td	{ border-bottom:1px solid black; font-weight:bold; }
	input[type='button']		{ width:115px; }
	#clearColors			{ display:none; }
</style>

Now the trick is getting it to display if there are highlighted table rows. Easy enough. For each of our existing methods that do the highlighting, after the highlighting is complete (after the each() method finishes running), simply manipulate the css property "display" to "inline":

$('#cheapstuff').click(function() {
	clearRows();
	$('.salePrice').each(function() {
		if ($(this).text() < 100)
		$(this).parent().css('backgroundColor', '#EFEF00');
	});
	$('#clearColors').css('display', 'inline');
});

$('#halfoff').click(function() {
	clearRows();
	$('#inventoryTable tbody tr').each(function() {
		var reg  = $(this).children(':eq(0)').text();
		var sale = $(this).children(':eq(1)').text();

		if (reg/sale > 2)
			$(this).css('backgroundColor', '#EFEF00');
	});
	$('#clearColors').css('display', 'inline');
});

Note that now, the last line of each handler method uses a jQuery selector to select the element with id="clearColors", and sets it css "display" property to "inline".

We've got one small addition left to make before putting it all together. Since we want the "Clear" button to be hidden when there are no highlighted table rows, we're going to hide the button when it's clicked. We currently have a handler method for it, so we'll just add a line of code to manipulate the css "display" property to "none":

$('#clearColors').click(function() {
	clearRows();
	$(this).css('display', 'none');
});

That should do it. We've now given the user the ability to quickly identify rows in the table that match different sets of criteria. The final code (copy/paste and run in a browser):

<html>
<head>
	<title></title>

	<style type="text/css">
		#inventoryTable			{ margin:0 0 12px 0; }
		#inventoryTable thead td	{ border-bottom:1px solid black; font-weight:bold; }
		input[type='button']		{ width:115px; }
		#clearColors			{ display:none; }
	</style>

	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
	<script type="text/javascript">
		$(document).ready(function() {
		
			$('#cheapstuff').click(function() {
				clearRows();
				$('.salePrice').each(function() {
					if ($(this).text() < 100)
					$(this).parent().css('backgroundColor', '#EFEF00');
				});
				$('#clearColors').css('display', 'inline');
			});
			
			$('#halfoff').click(function() {
				clearRows();
				$('#inventoryTable tbody tr').each(function() {
					var reg  = $(this).children(':eq(0)').text();
					var sale = $(this).children(':eq(1)').text();
			
					if (reg/sale > 2)
						$(this).css('backgroundColor', '#EFEF00');
				});
				$('#clearColors').css('display', 'inline');
			});
		
			function clearRows() {
				/* commenting this out.  see below:
				$('#inventoryTable tbody tr').each(function() {
					$(this).css('backgroundColor', '');
				});
				*/

				// as pointed out in the comments by Brian Swartzfager, this is a cleaner implementation:
				$('#inventoryTable tbody tr').css('backgroundColor', '');
			}
			
			$('#clearColors').click(function() {
				clearRows();
				$(this).css('display', 'none');
			});

		});
	</script>
</head>

<body>

<table id="inventoryTable" cellpadding="3" cellspacing="0">
<thead>
<tr>
	<td>Original Price</td>
	<td>Sale Price</td>
	<td>Description</td>
</tr>
</thead>
<tbody>
<tr>
	<td class="originalPrice">100.00</td>
	<td class="salePrice">65.00</td>
	<td>Green widget (Yellow stripes)</td>
</tr>
<tr>
	<td class="originalPrice">200.00</td>
	<td class="salePrice">110.00</td>
	<td>Lavender Widget (White dots)</td>
</tr>
<tr>
	<td class="originalPrice">200.00</td>
	<td class="salePrice">74.00</td>
	<td>Red Widget (Solid)</td>
</tr>
</tbody>
</table>

<div id="buttons">
	<input type="button" value="Items Under $100" id="cheapstuff" />
	<input type="button" value="Items 50% off" id="halfoff" />
	<input type="button" value="Clear" id="clearColors" />
</div>

</body>
</html>

Comments (4) | 3497 Views

Comments

Add Comment | Subscribe to Comments

  1. Brian Swartzfager's Gravatar

    # Posted Brian Swartzfager on 8/20/09 1:37 PM

    You could actually make the clearRows() function even simpler if you removed the use of the each() function and just attached the css() function to your selector (not sure if the code will show up here...):

    function clearRows() {
       $('#inventoryTable tbody tr').css('backgroundColor', '');
    }

  2. Charlie Griefer's Gravatar

    # Posted Charlie Griefer on 8/20/09 2:03 PM

    @Brian - Good catch. I was using .each() so much in the other methods I got into a rut :)

  3. Brian Swartzfager's Gravatar

    # Posted Brian Swartzfager on 8/21/09 3:38 AM

    No worries: happens to the best of us. :)

  4. Zloi's Gravatar

    # Posted Zloi on 3/3/10 6:18 AM

    I fond interesting solution for Rows background, the rows highlighting on mouse over, without JS.
    http://www.sopov.com/joomla-wordpress-tips-and-tri...
    Works in all browsers. For IE6/7/8 tr{ position: relative; } and td{ background-image: none } and for Safari i use negative background position for each TD.

Add Comment