Compare Selected Items Side by Side
Get the Code for this Tutorial
View a Working Example of This Code
Comment on this Tutorial
This Tutorial will show you how to allow your web site's users to compare selected items side by side. Your items could be anything from products for sale to statistical information. I will be using cars for this example.
The first step is for the user to make a selection of items to compare from the list of available items. Then we show the user a side by side comparison of the selected items. From there the user can continue adding items to be compared, or remove selected items from the comparison view.
We'll start with the item selection page first. This page will display all the available items from the database for the user to select which ones they want to compare by using check boxes.
File 1: compare_list.cfm
The variable 'session.compareID' is used to hold a comma separated list of IDs of the items to compare. We could just go from form to action page, but this way lets the user browse the site, and come back to the comparison view page and still have their selection available.
<cfparam name="session.compareID" default="0">
The query here is simple. Use the SQL at the end of this tutorial (or click here to download it) to build this database on your server, or modify the SQL statements in this tutorial to work with your dsn and table information.
<cfquery datasource="#dsn#" name="getData">
SELECT id,name,year FROM cfml_example_data2
</cfquery>
If our session variable 'session.compareID' is not still the default value, then there are some items selected already. We will show a little message and a link to the comparison view page so the user can easily get back to the comparison view page to review their selections.
<cfif NOT session.compareID EQ 0>
<cfoutput>
<a href="compare_view.cfm">View the #listLen(session.compareID)# Items</a>
you have already selected, or <br/>
</cfoutput>
</cfif>
We next build a form that will have a list of items and check boxes to select which items to compare.
Choose Items to Compare<br/>
<form action="compare_view.cfm" method="post">
Begin the output of the data from the query we made above in this file.
<cfoutput query="getData">
Create check boxes with the html input tag. The name of all the check boxes is 'compareID'. When you have multiple input tags with the same name in the same form, the values are passed as a comma separated list. The form will send this comma separated list to our comparison view page.
Also, we are dynamically checking or un-checking the check boxes depending on if the user has already checked or un-check them. If the id from the database is found in the session variable 'session.compareID', then the user has already checked the box, and we should keep it checked so they don't have to re-check it if they come back to this page to add more items.
Next to the check boxes is the item name. In this case, I use the car year and name. Also close the cfoutput tag.
<input type="checkbox" name="compareID" value="#getData.id#" <cfif listFind(session.compareID,getData.id)>checked="checked"</cfif> />
#getData.year# #getData.name#<br/>
</cfoutput>
<br/>
A submit button and closing form tag will finish up this page.
<input type="submit" value="Compare Choices" name="addIDs" />
</form>
File 2: compare_view.cfm
The file 'compare_view.cfm' is the template that will show the users selected choices in detail.
Use cfparam with form variable 'form.compareID' so that we avoid undefined variable errors, especially if no selection is made. (If no boxes are checked, the check box name and value will not be sent. This is how html check boxes and radio selects work.)
<cfparam name="form.compareID" default="">
Now we check to see if the form that contained the selection choices has been submitted, and if it has, set the value of the check boxes to a session variable, 'session.compareID'.
<cfif structKeyExists(form,"addIDs")>
<cfset session.compareID = form.compareID>
</cfif>
This next bit of code simple ensures that 'session.compareID' has some sort of value (0) so that the ColdFusion list functions used with this variable later will not fail.
<cfif NOT len(session.compareID)>
<cfset session.compareID = 0>
</cfif>
Now we query the items table to get the details of the items. Notice the WHERE clause. We use the IN() syntax to provide the database with a list of values to match. We want all the rows in the database where ID is in our list of compareIDs.
Make sure you use the list="Yes" attribute in the cfqueryparam tag, so that CF knows that we want to use a comma separated list of numeric values, rather then a string.
<cfquery datasource="#dsn#" name="getData">
SELECT id,name,year,hp,trq,valves,displacement,doors,drive,cylinders FROM cfml_example_data2
WHERE id IN(<cfqueryparam cfsqltype="CF_SQL_INTEGER" list="Yes" value="#session.compareID#">)
</cfquery>
As we output the results for the user to view their selections, we also are going to build a form so that the user can check off items to remove form the comparison list. Start without form tag, and use action="compare_remove.cfm". Compare_remove.cfm is a simple file we will build after this one.
<form action="compare_remove.cfm" method="post">
This cfoutput and the link lets the user go back to the Item Selection screen to select items again or change the selection.
<cfoutput>
<a href="compare_list.cfm">Back to Item Selection</a>
</cfoutput>
Build the table with the header information to display the comparison items.
<table>
<tr>
<td>Remove</td>
<td>Year</td>
<td>Car</td>
<td>HP</td>
<td>Trq.</td>
<td>Cyl.</td>
<td>Valves</td>
<td>Displacement</td>
<td>Drive</td>
<td>Doors</td>
</tr>
Use cfoutput with the query attribute to output the selected items from the query above (getData).
<cfoutput query="getData">
<tr>
Make html input tags with type="checkbox" and name="removeIDs" for the user to select items to remove from the item comparison view. A user may select several items to compare, and then want to remove some, one at a time, to narrow their research.
<td><input type="checkbox" name="removeIDs" value="#id#" /></td>
Finish the output of the table data. This part is easy enough. Close the cfoutput and table tags also.
<td>#year#</td>
<td>#name#</td>
<td>#hp#HP</td>
<td>#trq#lb-ft</td>
<td>#cylinders#</td>
<td>#valves#</td>
<td>#displacement#l</td>
<td>#drive#</td>
<td>#doors#</td>
</tr>
</cfoutput>
</table>
Make the submit button for the user to remove selected items, and close up the finishing form tag.
<input type="submit" name="update" value="Remove Checked" />
</form>
File 3: compare_remove.cfm
The file compare_remove.cfm will update the session variable to remove the items marked for removal by the user. It is very simple, but I'll take you through it anyway.
First, check that the form was submitted by looking for the existance of the our submit button that we named update in the form in compare_view.cfm.
<cfif structKeyExists(form,"update")>
If the form has been submitted, use cfparam to set a default value for 'form.removeIDs'. Since 'form.removeIDs' is a check box the form variable will not be defined it left unchecked.
<cfparam name="form.removeIDs" default="">
The value of form variable 'form.removeIDs' will be a comma separated list if any items have been checked off for removal.
We will loop that list using the ColdFusion loop tag and the list attribute. Our list is the 'form.removeIDs' form variable.
<cfloop list="#form.removeIDs#" index="i">
During the loop we need to compare the IDs in 'form.removeIDs' and 'session.compareID'. If there is an ID in 'form.removeIDs' that is also in 'session.compareIDs' we use listFind() to get the position of the matching ID, and listDeleteAt() to remove it from the 'session.compareID' list of IDs.
<cfif listFind(session.compareID,i)>
<cfset session.compareID = listDeleteAt(session.compareID,listFind(session.compareID,i))>
</cfif>
Close the loop.
</cfloop>
And close the cfif that we used to check if the form was submitted. Then use cflocation to take the user back to 'compare_view.cfm' to view their newly updated selection.
</cfif>
<cflocation addtoken="No" url="compare_view.cfm">
Using 'Product Comparisons' or side by side comparisons of this type can greatly increase the user experience for visitors on your sites. This is just the beginning of what you can do with this feature!
____________
Tutorial Code
Download the Database<!--------------------------------------------
Kevin Sargent
January 12th 2006
http://www.lot-o-nothin.com/cfml/
Please Give Credit Where Used.
--------------------------------------------->
<!---{
========================
FILE: compare_list.cfm
=========================
}--->
<cfparam name="session.compareID" default="0">
<cfquery datasource="#dsn#" name="getData">
SELECT id,name,year FROM cfml_example_data2
</cfquery>
<cfif NOT session.compareID EQ 0>
<cfoutput>
<a href="compare_view.cfm">View the #listLen(session.compareID)# Items</a> you have already selected, or <br/>
</cfoutput>
</cfif>
Choose Items to Compare<br/>
<form action="compare_view.cfm" method="post">
<cfoutput query="getData">
<input type="checkbox" name="compareID" value="#getData.id#" <cfif listFind(session.compareID,getData.id)>checked="checked"</cfif> />
#getData.year# #getData.name#<br/>
</cfoutput><br/>
<input type="submit" value="Compare Choices" name="addIDs" />
</form>
<!---{
========================
FILE: compare_view.cfm
=========================
}--->
<cfparam name="form.compareID" default="">
<cfif structKeyExists(form,"addIDs")>
<cfset session.compareID = form.compareID>
</cfif>
<cfif NOT len(session.compareID)>
<cfset session.compareID = 0>
</cfif>
<cfquery datasource="#dsn#" name="getData">
SELECT id,name,year,hp,trq,valves,displacement,doors,drive,cylinders FROM cfml_example_data2
WHERE id IN(<cfqueryparam cfsqltype="CF_SQL_INTEGER" list="Yes" value="#session.compareID#">)
</cfquery>
<form action="compare_remove.cfm" method="post">
<cfoutput>
<a href="compare_list.cfm">Back to Item Selection</a>
</cfoutput>
<table>
<tr>
<td>Remove</td>
<td>Year</td>
<td>Car</td>
<td>HP</td>
<td>Trq.</td>
<td>Cyl.</td>
<td>Valves</td>
<td>Displacement</td>
<td>Drive</td>
<td>Doors</td>
</tr>
<cfoutput query="getData">
<tr>
<td><input type="checkbox" name="removeIDs" value="#id#" /></td>
<td>#year#</td>
<td>#name#</td>
<td>#hp#HP</td>
<td>#trq#lb-ft</td>
<td>#cylinders#</td>
<td>#valves#</td>
<td>#displacement#l</td>
<td>#drive#</td>
<td>#doors#</td>
</tr>
</cfoutput>
</table>
<input type="submit" name="update" value="Remove Checked" />
</form>
<!---{
========================
FILE: compare_remove.cfm
=========================
}--->
<cfif structKeyExists(form,"update")>
<cfparam name="form.removeIDs" default="">
<cfloop list="#form.removeIDs#" index="i">
<cfif listFind(session.compareID,i)>
<cfset session.compareID = listDeleteAt(session.compareID,listFind(session.compareID,i))>
</cfif>
</cfloop>
</cfif>
<cflocation addtoken="No" url="compare_view.cfm">