http://www.developer.com/services/article.php/3619511/Decision-Making-Flags-The-How-and-Why.htm
Have you ever wanted to easily view information that is critical to your decision making process, yet there are other details that would be nice to know; however, those details are not as important to the final decision? A brief, but common usage scenario probably will illuminate what I'm attempting to convey. Imagine that you want to search for an airline flight from one city to another on a specific date. There are certain items that are probably more important in your decision of which flight to choose. Such items may include: These search results adequately answer your initial, primitive question of: "What flights are available from [departure city] to [destination city] on [date]?" However, ultimately you would like to be able to incorporate your preferences in with your final decision, yet your preferences aren't necessarily requirements. Such questions, or preferences, related to the flight may include: As you can imagine, if you were provided with all of this information at once, the user interface could become quite cluttered, perhaps overwhelming, and in the case of your lay-over question, perhaps inadequate. If you displayed our results using an archetypal grid, perhaps you would see the following: Now, pretend you were provided only with the most important information and from there began your decision making process. You could expect to traditionally see something similar to the following: Once a user selects an item from the list above, that user could be redirected to a screen that provides details related to the selected flight. That interface could look something like the following: There are still some problems surrounding this interface. Navigating through various pages to collect the desired information is both cumbersome and inefficient. By implementing an interface that is both readily accessible and intuitive, you can provide an efficient and powerful decision making tool. To accomplish this, you will implement a slightly unique graphical construct. For the purpose of this article, you will refer to this construct as a "Flag" (this name is derived from the shape; it actually reminds me of one of those toy guns where the flag pops out and says "bang"). See how it appears below: Creating flags within tabular data creates several interesting challenges. Throughout this article, you will address the implementation of flags within tabular data and examine the basics. The remainder of this article will use snippets from the source code that you can get here. Begin by creating the HTML you would initially see on the page. For the sake of simplicity, you will only be examining a single record table. In addition, you will attempt to keep the code simple to focus on the flag implementation. You will notice that you utilize a basic table element that contains the results from your initial question. Each tr element in the table represents one of the results from your search. Snippet 1 After you have created entries for each result, you need to create the "flag" portion. Each flag contains the informative details of each result. In the example, a flag contains the airline information, whether there is a meal or snack, whether there is an in-flight movie, and flight schedule information to help you see layover related information. To construct the flag, you must implement the following steps: Using the code you implemented from Snippet 1, you now need to add the code, displayed in blue, from Snippet 2. Snippet 2 Good news! You are done constructing the core HTML that your flags will utilize. However, you are not yet finished. At this point, you have all of the elements in place; however, you need to implement the behavior. The behavior handles the interaction between the user and the elements. Ultimately, you want to have a flag that drapes over other results when a user hovers over a result. The process of displaying and hiding the flag will be fulfilled via some JavaScript. There are four events that you must watch for to properly display and hide the flag. These events are: Before you implement the code to handle these events, you must identify who will be responsible for employing these events. To accomplish this, you must implement some consistent naming standard that will assist you in assigning the appropriate event handlers. Revisit Snippet 2 and notice that you are using the following naming structure: Now that you have implemented a naming schema for the necessary components, you are ready to add the JavaScript that will handle the events accordingly. In the example, you will place the JavaScript in an external .js file and reference it from your HTML page. The JavaScript I am referring to is listed in Snippet 3. Snippet 3 The comments within the JavaScript explain what is occurring. One thing to note, however, is that in the Initialize function you begin at an index of 1. This may seem a bit preternatural if you are used to 0-based indexing. The reason you do this is to prevent adding event handlers to the column heading row, which would cause a JavaScript error. To complete your implementation of your flags, you need to perform one more little task. After providing the appropriate linking to your .js file in the head section of the HTML file, you need to add a call to initialize your table from the body element in your HTML code. You can see the additions, in blue, within Snippet 4. Congratulations! You have put together an extremely valuable decision-centric interface. There are numerous ways you could enhance this UI component, including various style enhancements and employing AJAX to populate your hidden results (flags) more efficiently. However, the purpose of this article was to provide an introduction to this complex UI component. I hope you have enjoyed this article and I hope to see this component employed on your site soon!
Decision Making Flags: The How and Why
July 12, 2006




Implementation
<html>
<head>
<style type='text/css'>
tr.gridHeader {background-color:#3891A7;font-weight:bold;}
tr.flagStaff {background-color:#E7DEC9;}
td.gridHeader {color:black; border-bottom:solid 2px black;}
td.spacer {width:6px;}
</style>
</head>
<body>
<table id='RecordsTable' border='0' cellpadding='0'
cellspacing='0'>
<tr class='gridHeader'>
<td class='gridHeader'>Destination</td>
<td class='spacer'></td>
<td class='gridHeader'>Cost</td>
<td class='spacer'></td>
<td class='gridHeader'>Departure</td>
<td class='spacer'></td>
<td class='gridHeader'>Arrival</td>
<td class='spacer'></td>
<td class='gridHeader'>Total Travel Time</td>
</tr>
<tr class='flagStaff' id='record1'>
<td>Indianapolis</td>
<td class='spacer'></td>
<td>$236</td>
<td class='spacer'></td>
<td>4:20 p.m.</td>
<td class='spacer'></td>
<td>9:05 p.m.</td>
<td class='spacer'></td>
<td>3hr 45min</td>
</tr>
</table>
</body>
</html>
<html>
<head>
<style type='text/css'>
tr.gridHeader {background-color:#3891A7;font-weight:bold;}
tr.flagStaff {background-color:#E7DEC9;}
tr.flagStaffHover {background-color:#3891A7;color:white;
cursor:pointer;}
td.gridHeader {color:black; border-bottom:solid 2px black;}
td.spacer {width:6px;}
span.flag{display:none;position:absolute;width:100%;
background-color:#3891A7;color:white;}
</style>
</head>
<body>
<table id='RecordsTable' border='0' cellpadding='0'
cellspacing='0'>
<tr class='gridHeader'>
<td class='gridHeader'>Destination</td>
<td class='spacer'></td>
<td class='gridHeader'>Cost</td>
<td class='spacer'></td>
<td class='gridHeader'>Departure</td>
<td class='spacer'></td>
<td class='gridHeader'>Arrival</td>
<td class='spacer'></td>
<td class='gridHeader'>Total Travel Time</td>
</tr>
<tr class='flagStaff' id='record1'>
<td>Indianapolis </td>
<td class='spacer'></td>
<td>$236</td>
<td class='spacer'></td>
<td>4:20 p.m.</td>
<td class='spacer'></td>
<td>9:05 p.m.</td>
<td class='spacer'></td>
<td>3hr 45min</td>
</tr>
<tr class='flagStaffHover' id='hiddenRecordFlag1'>
<td colspan='4'></td>
<td colspan='5'> <span id='record1Flag' class='flag'>
<table border='0' cellpadding='0' cellspacing='0'>
<tr class='selectedRow'>
<td align='left'>Airline: </td>
<td align='left'>Dodo Airway</td>
<td class='flagSpacer'></td>
<td align='left'>Movie: </td>
<td align='left'>Yes</td>
</tr>
<tr class='selectedRow'>
<td align='left'>Meal: </td>
<td align='left'>Yes</td>
<td class='flagSpacer'></td>
<td align='left'>Snack: </td>
<td align='left'>No</td>
</tr>
<tr class='selectedRow'>
<td colspan='2'>This is a direct flight</td>
</tr>
</table>
</span></td>
</tr>
</table>
</body>
</html>
var selectedRowId = null;
// ==========================================================
// Adds the appropriate event handlers to the flagged entries
// ==========================================================
function Initialize()
{
var table = document.getElementById("RecordsTable");
for (i=1; i<table.rows.length; i++)
{
var tableRow = table.rows[i];
if (tableRow.id.indexOf("hiddenRecordFlag") == -1)
{
tableRow.onmouseover = OnFlagStaffOver;
tableRow.onmouseout = OnFlagStaffOut;
var flag = document.getElementById(tableRow.id + "Flag");
(flag != null)
{
flag.onmouseover = OnFlagOver;
flag.onmouseout = OnFlagOut;
}
}
}
}
function OnFlagStaffOver()
{
ShowFlag(this.id);
}
function OnFlagStaffOut()
{
HideFlag(this.id);
}
function OnFlagOver()
{
var rowId = this.id.substring(0, this.id.length-4);
ShowFlag(rowId);
}
function OnFlagOut()
{
var rowId = this.id.substring(0, this.id.length-4);
HideFlag(rowId);
}
// =======================================
// Displays the flag associated with a row
// =======================================
function ShowFlag(rowId)
{
// Determine if anything needs to be done
if (rowId == selectedRowId)
return;
// Determine if another flag needs to be hidden
if (rowId != selectedRowId)
{
if (selectedRowId != null)
{
// Alter the flag staff
var selectedFlagStaff =
document.getElementById(selectedRowId);
selectedFlagStaff.className = "";
// Hide the flag
var selectedFlag =
document.getElementById(selectedRowId + "Flag");
selectedFlag.style.display = "none";
}
}
// Update the style of the flag staff that is selected
selectedRowId = rowId;
var flagStaff = document.getElementById(rowId);
flagStaff.className = "flagStaffHover";
// Display the flag of the selected flag
var flag = document.getElementById(rowId + "Flag");
flag.style.display = "block";
}
// ====================================
// Hides the flag affiliated with a row
// ====================================
function HideFlag(rowId)
{
// Update the style of the flag staff that has been exited
var flagStaff = document.getElementById(rowId);
flagStaff.className = "flagStaff";
// Hide the flag
var flag = document.getElementById(rowId + "Flag");
flag.style.display = "none";
// Reset the selectedRowId
selectedRowId = null;
}
<html>
<head>
<script type='text/javascript' src='flag.js'></script>
<style type='text/css'>
tr.gridHeader {background-color:#3891A7;font-weight:bold;}
tr.flagStaff {background-color:#E7DEC9;}
tr.flagStaffHover {background-color:#3891A7;color:white;
cursor:pointer;}
td.gridHeader {color:black; border-bottom:solid 2px black;}
td.spacer {width:6px;}
span.flag{display:none;position:absolute;width:100%;
background-color:#3891A7;color:white;}
</style>
</head>
<body onload='Initialize();'>
<!-- Remainder of code from the previous snippet -->
</body>
</html>
Conclusion
Downloads
About the Author

Chad Campbell (MCSD, MCTS) is a solutions developer for mid to large-sized organizations. Chad is a thought leader with Crowe Chizek in Indianapolis, Indiana. Chad specializes in Web-based solutions. He can be reached at cacampbell@crowechizek.com.