The i-Technology Media!
Register | Log in
   
 
.NET  ·  AJAX  ·  CLOUD  ·  ECLIPSE  ·  FLEX  ·  OPEN WEB  ·  iPHONE  ·  JAVA  ·  LINUX  ·  OPEN SOURCE  ·  ORACLE  ·  PBDJ  ·  SEARCH  ·  SILVERLIGHT  ·  SOA  ·  VIRTUALIZATION  ·  WEB 2.0  ·  WIRELESS  ·  XML
Comments
Drool, Britannia? Is the UK Failing the Cloud?
By Roger Strukhoff
Richard Davies wrote: The UK has a good crop of technology pioneers in cloud computing - for example ElasticHosts, FlexiScale, Flexiant, OnApp - and also some strong government initiatives such as G-Cloud. We will have to see whether this kind of technical leadership converts into swift mass-market adoption or not.
Jan. 8, 2012 11:38 AM EST
read more & respond »
Cloud Expo on Google News
Did you read today's front page stories & breaking news?

Cloud Expo & Virtualization 2011 West
Keynotes
Oracle
Opening Keynote | An Enterprise Cloud for Business-Critical Applications
Abiquo
Day 2 Keynote | The Enterprise Cloud Tightrope - Balancing for Success
Akamai
Day 3 Keynote | The DNA of an Enterprise Cloud
DIAMOND SPONSOR:
Oracle
Many Clouds, Many Choices'Cloud
PLATINUM PLUS SPONSORS:
Abiquo
Enterprise Cloud Best Practices - Town Hall - Join the discussion…
PLATINUM SPONSORS:
Intel
Progressing Toward the Federated, Automated and Client-Aware Cloud
New Relic
How to build an app with Twitter-like throughput
Rackspace
Computing in the Cloud Era
GOLD SPONSORS:
Gale Technologies
Practical Cloud Migration
IBM
Re-think IT. Re-inventing Business.
Intel/McAfee
Identity Driven Security in the Cloud
PerspecSys
Hackers Hackers Everywhere, Is My Public Cloud That Safe?
Red Hat
Unlock the Value of the Cloud
SHI
Mission Critical Applications and the Cloud - Myth or Reality?
SoftLayer
Not Your Grandpa's Cloud
Terremark
Integrating Enterprise Clouds
VMware
Upgrade to a vCloud
POWER PANELS:
Cloud Expo Silicon Valley: CTO Power Panel
Cloud Expo Silicon Valley: CEO Power Panel
Cloud Expo Silicon Valley: Cloud SuperStars Panel
Cloud Expo Silicon Valley: CloudNOW Panel
Click For 2010 West
Event Webcasts
Cloud Expo & Virtualization 2011 East
DIAMOND SPONSOR:
Dell
Dell & VMware Deliver the Enterprise Hybrid Cloud
PLATINUM PLUS SPONSORS:
Abiquo
Are Financial Services Organizations Risking Security by Avoiding Cloud Computing?
Oracle
From Consolidation to Enterprise Private PaaS
PLATINUM SPONSORS:
Intel
Driving the Transformation to Next Generation Cloud Data Centers
Rackspace
The Inevitability of an Open Cloud
GOLD SPONSORS:
CA Technologies
Follow YOUR path to Cloud Computing
Interxion
Who Keeps the Cloud in the Air?
Microsoft
Patterns for Cloud Computing
PerspecSys
War in the Clouds: Are you ready?
ServiceMesh
The Big Win: Stop Playing Small-Ball with Your Cloud Strategy
Terremark
Evaluating Enterprise Clouds
Xiotech
Cloud Storage: Myths and Realities
POWER PANELS:
Cloud Expo New York: CTO Power Panel
Cloud Expo New York: CEO Power Panel
Cloud Expo New York: CMO Power Panel
Cloud Expo New York: Wrap-Up Power Panel
Click For 2010 West
Event Webcasts
Live Google News by SYS-CON!
Top Three Links You Must Click On


Fusebox
Don't Sell the Site, Sell the Quizzle
Don't Sell the Site, Sell the Quizzle

By: Hal Helms
Sep. 18, 2003 12:00 AM

One of the great things about developing for the Web is the fun factor. While our grimmer, more serious IT cousins are exiled in lands populated by such dread monsters as COBOL and FORTRAN, and must do daily battle with the demon, MainFrame, our lot is far more pleasant.

This article, while it will do nothing to stave off global warming, will give you the tools you need to increase your own fun factor, while offering your clients a very nice interactive feature for their web sites and applications. So, after a moment of silence for our ill-starred comrades...let's get this party started!

Overview: What We Want To Accomplish
You've probably seen those small, interactive quizzes on such sites as ESPN. They pull the reader in by asking their opinion on "Who do you want to break Roger Maris' homerun record?" Then they offer a choice of radio buttons corresponding to the leaders in the homerun derby.

 

Answer the question and you'll get to see a colorful bar chart showing how others have answered.

 

This seemingly trivial mini-application can offer real value to your clients. Unlike page-long forms that site visitors deplore, these "quizzles" are quick to take and it's fun to see how others have responded. Using these quizzles over time, your clients can build up a database of how their users feel and think. Such knowledge of their customers and prospects can only help your clients in the fiercely competitive world they inhabit.

Coding For Reuse and Maintainability
In our shop, we constantly try to make our code reusable and maintainable. It turns out that these two go nicely together: code that is written to be maintainable lends itself to reusability. It also works the other way around.

Your quizzle application is likely to be a hit with your clients. They will want to be able to maintain the application by adding or deleting quizzles and by setting in what order quizzles are displayed. A great selling feature of our quizzle app is your clients' ability to do this themselves, without incurring additional or continuing costs. If we build this right, everyone wins: you'll have a popular app that you develop once and sell many times and your clients buy the applet once and maintain it themselves.

The Database
We will use a SQL database to store information about the quizzle itself and user responses to each quizzle offered. For illustrative purposes, we'll use Microsoft Access; you will probably require something more robust when actually deploying your quizzle app. The structure looks like this:

 

Administrative form
Since users will be administering the quizzle app long after you've made your first million; you'll need to provide a way for them to perform administrative functions. These are:

  • Add new question
  • Edit existing question
  • Delete existing question
The Quizzle Admin Menu file accomplishes this.

 

quizzleAdmin.cfm

<!--- fileName: quizzleAdmin.cfm
      programmer: hal.helms@utaweb.com
               date: 9/1/98
         requires: nothing
          accepts: url.orderField
--->
   
<!--- Set default column to sort by --->
<cfparam name="orderField" default="qQuestion">

<!--- Get list of all quizzles to show administrator --->
<cfquery
   datasource="quizzle" 
   name="getQuizzles"> 
   SELECT * FROM Quizzles 
   ORDER BY #orderField#
</cfquery>

<html>
<head>
   <title>A UTA Internet Solutions Web application</title>
</head>

<body bgcolor="white">
<font face="arial, helvetica, sanserif" size="2">

<table border="0" cellpadding="3">
<tr>
   <td colspan="5" align="middle">
      <IMG 
         alt="Quizzle Admin Menu" 
         border=0 
         height=60 
         src="images\bnrQuizzleAdminMenu.gif" 
         width=400>
   </td>
</tr>
<tr>
   <td colspan="5" align="middle">
      <a href="quizzleEntry.cfm">
         <img 
            src="images/btnAdd.gif" 
            width=132 
            height=26 
            alt="Add Quizzle" 
            border="0">
      </a>
   </td>
</tr>
<tr>
   <td></td>
   <td align="center">
      <b>
      <a href="quizzleAdmin.cfm?orderField=qQuestion">
         Quizzle
      </a>
      </b>
   </td>
   <td>
      <b>
      <a href="quizzleAdmin.cfm?orderField=qDateStart">
         Start Date
      </a>
      </b>
   </td>
   <td>
      <b>
      <a href="quizzleAdmin.cfm?orderField=qDateStop">
         Stop Date
      </a>
      </b>
   </td>
   <td></td>
</tr>
<cfoutput query = getQuizzles>
<tr>
   <td>
      <a href="quizzleEntry.cfm?qID=#qID#">
         <IMG 
            alt=Edit 
            border=0 
            height=14 
            src="images/btnEdit.gif" 
            width=45>
      </a>
   </td>
   <td>#qQuestion#</td>
   <td>#DateFormat(qDateStart, "m/d/yy")#</td>
   <td>#DateFormat(qDateStop, "m/d/yy")#</td>
   <td align="right">
      <a href="deleteQuizzle.cfm?qID=#qID#">
         <IMG 
            alt=Delete 
            border=0 
            height=14 
            src="images/btnDelete.gif" 
            width=45>
      </a>
   </td>
</tr>
</CFOUTPUT>
</table>
</font>
</body>
</html>

This is a pretty straightforward form. The only thing of slight interest occurs where we give the user the ability to sort by various table columns. Prior to implementing this, we were getting many requests to download tables into a spreadsheet format. In speaking with and observing users, we found that adding this small feature reduced spreadsheet format requests by over 70%.

We accomplish this by using the <cfparam> tag to create a variable called "orderField". Why not just use <cfset> to set the value? We only want to initialize this variable -- that is, assign it a default value. When the user clicks on the heading of any of the other columns, a new value will be assigned to it, overriding the default value. Whereas <cfset> would always assign a value to this variable, <cfparam> assigns one only if no value exists.

Since we're committed to code reuse, we'll create a single form that will handle both edits and additions to the database.

 

Quizzle Entry form -- in add mode
Note that the same URL is invoked to add a new quizzle and to edit an existing one. If you haven't created double-duty forms before, you may want to spend a few minutes looking over this over.

quizzleEntry.cfm

<!--- fileName: quizzleEntry.cfm
      programmer: hal.helms@utaweb.com
            date: 9/1/98
         requires: nothing
          accepts: qID = [table quizzles primary key]
--->
  
 
<!--- initialize fields --->
<cfparam name="getQuizzle.qID" default="">
<cfparam name="getQuizzle.qQuestion" default="">
<cfparam name="getQuizzle.q1" default="">
<cfparam name="getQuizzle.q2" default="">
<cfparam name="getQuizzle.q3" default="">
<cfparam name="getQuizzle.q4" default="">
<cfparam name="getQuizzle.qAnswer" default="">
<cfparam name="getQuizzle.qDateStart" default="">
<cfparam name="getQuizzle.qDateStop" default="">
<cfparam name="getQuizzle.giveCorrectAnswer" default="yes">

<!--- Are we adding a new record or editing an existing one? --->
<cfif IsDefined("url.qID")>
   <cfset mode = "edit">
<cfelse>
   <cfset mode = "add">
</cfif>

<!--- if we're editing, find out info on quizzle --->
<cfif #mode# is "edit">
   <cfquery 
      datasource="quizzle"
      name="getQuizzle">
      SELECT * FROM Quizzles WHERE qID = #url.qID#
   </cfquery>
</cfif>

<html>
<head>
   <title>A UTA IS Web application</title>
</head>

<body bgcolor="white">
<font face="arial, helvetica, sanserif" size="2">

<form action="doQuizzleEntry.cfm" method="post">
<cfoutput>
<table bgcolor="FFFFFF" cellspacing="2" cellpadding="2" border="0">
<tr>
   <td align="center" colspan="2">
      <cfif #mode# is "edit">
         <img 
            src="images/bnrEditingAquizzle.gif" 
            width=400 
            height=60 
            alt="Editng a Quizzle" 
            border="0">
         <input 
            type="hidden" 
            name="qID" 
            value="#url.qID#">
      <cfelse>
         <img 
            src="images/bnrAddingAquizzle.gif" 
            width=400 
            height=60 
            alt="Editng a Quizzle" 
            border="0">
      </cfif>
   </td>
</tr>
<tr>
   <td align="right" valign="top">
      Quizzle Question
   </td>
   <td valign="top">
      <input
         type="Text" 
         name="qQuestion" 
         value="#getQuizzle.qQuestion#" 
         size="40" 
         maxlength="255">
   </td>
</tr>
<tr>
   <td colspan="2">
      <i>You can fill in up to four responses for this quizzle.</i>
   </td>
</tr>
<tr>
   <td align="right" valign="top">
      Response 1
   </td>
   <td valign="top">
      <input 
         type="Text" 
         name="q1" 
         value="#getQuizzle.q1#" 
         size="12" 
         maxlength="22">
   </td>
</tr>
<tr>
   <td align="right" valign="top">
      Response 2
   </td>
   <td valign="top">
      <input 
         type="Text" 
         name="q2" 
         value="#getQuizzle.q2#" 
         size="12" 
         maxlength="22">
   </td>
</tr>
<tr>
   <td align="right" valign="top">
      Response 3
   </td>
   <td valign="top">
      <input 
         type="Text" 
         name="q3" 
         value="#getQuizzle.q3#" 
         size="12" 
         maxlength="22">
   </td>
</tr>
<tr>
   <td align="right" valign="top">
      Response 4
   </td>
   <td valign="top">
      <input 
         type="Text" 
         name="q4" 
         value="#getQuizzle.q4#" 
         size="12" 
         maxlength="22">
   </td>
</tr>
<tr>
   <td align="right" valign="top">
      And the answer is...
   </td>
   <td valign="top">
      <input 
         type="Radio" 
         name="qAnswer" 
         value="q1"
         <cfif #getQuizzle.qAnswer# is "q1"> checked</cfif>
         >
         Response 1   
         <br>
      <input 
         type="Radio" 
         name="qAnswer" 
         value="q2"
         <cfif #getQuizzle.qAnswer# is "q2"> checked</cfif>
         >
      Response 2   
         <br>
    <input 
         type="Radio" 
         name="qAnswer" 
         value="q3"
         <cfif #getQuizzle.qAnswer# is "q3"> checked</cfif>
         >
         Response 3   
         <br>
    <input 
         type="Radio" 
         name="qAnswer" 
         value="q4"
         <cfif #getQuizzle.qAnswer# is "q4"> checked</cfif>
         >
         Response 4  
   </td>
</tr>
<tr>
   <td align="right">
      Show Correct Answer?
   </td>
   <td>
      <input 
         type="Radio" 
         name="giveCorrectAnswer" 
         value="yes"
         <cfif #getQuizzle.giveCorrectAnswer# is "yes"> checked</cfif>
         >
         Yes
         <br>
      <input 
         type="Radio" 
         name="giveCorrectAnswer" 
         value="no"
         <cfif #getQuizzle.giveCorrectAnswer# is "no"> checked</cfif>
      >
      No
   </td>
</tr>
<tr>
   <td align="right">
      Starting Date
   </td>
   <td>
      <input 
         type="text" 
         size="12" 
         name="qDateStart" 
         value="#DateFormat(getQuizzle.qDateStart, "m/d/yy")#"
         >
   </td>
</tr>
<tr>
   <td align="right">
      Ending Date
   </td>
   <td>
      <input 
         type="text" 
         size="12" 
         name="qDateStop" 
         value="#DateFormat(getQuizzle.qDateStop, "m/d/yy")#"
         >
   </td>
</tr>
<tr>
   <td colspan="2" align="center">
      <input 
         type="Submit" 
         value="      OK      "
         >
   </td>
</tr>
</table>
</cfoutput>
</form>
</font>
</body>
</html>

 

Same form -- in edit mode
The biggest problem presented by double-duty forms is that edit forms need to present the information stored in the database for this record while new entry forms have no existing information.

We know that if we will be editing a record, the record's primary key will be passed to us, usually as a URL or a hidden form variable. Once we receive this, we will query the database for the existing information about this particular record.

Let's assume we call this query "getQuizzle." Once this query is run, we will get back a number of variables, all with the "getQuizzle" prefix. We will use the values in these variables to fill in the edit form field values. The variable "getValue.qQuestion" provides us with the information needed for the qQuestion edit field. We will set the "value" parameter of the <input> tag to "#getQuizzle.qQuestion#". The same is true for all the edit fields, their "value" parameters are set to the query variables.

What happens if we are asked to process a new entry? In that case, we will have no primary key passed. There will be no query to run and no query variables. Yet, we have already set the "value" parameters of our form input tags to reflect the results of a run query.

The <cfparam> tag makes this easy. We can initialize these variables to an empty string, even before we know whether we are in "add" or "edit" mode. If we are adding a new entry, we simply have an empty string in our input fields. This causes no problem for inserting new records. Where we are asked to edit an existing record, the value of the "getQuizzle" variables will be overridden when the query is run. Now, regardless of the mode our form is in, no code will break.

Finally, we must give the administrative user a chance to delete quizzles. The action for this is simple enough and is called from quizzleAdmin.cfm when the administrator clicks the "Delete" button.

deleteQuizzle.cfm

<!--
   Filename:  deleteQuizzle.cfm
      Date:  9/6/98
Created by:  hal.helms@utaweb.com
    Expects:  qID
 -->  
<cfquery 
   datasource="quizzle" 
   name="deleteQ">
   DELETE * FROM Quizzles WHERE qID = #url.qID#
</cfquery> 
<html>
<head>
   <title>A UTA IS Web application</title>
</head>

<body bgcolor="white">
<font face="arial, helvetica, sanserif" size="2">
Alas, poor Quizzle -- I knew him well.
</font>
</body>
</html>

You can decide for yourself whether you wish to present a "nag" screen that asks the user "Are you really, really sure you want to delete this quizzle? Have you considered counseling?"

Of Quizzles and Custom Tags
Quizzles are meant to be easy to set up and use. Ideally, we want to keep all the fussy code away from the page that holds our quizzle and ColdFusion offers us a wonderful means for doing just that. Custom tags are an ingenious invention that allows us to take ColdFusion code -- even whole ColdFusion pages -- and treat them as if they were one more ColdFusion tag.

If you haven't used custom tags before, I hope this experience will convince you how indispensable this mechanism is. Structurally, they fall somewhere between functions and objects, delivering a much higher level of encapsulation than functions though falling short of objects. And while the initiation into true object oriented languages involves the use of candles and requires you to pledge your first-born, custom tags are much easier to master. In fact, we will create one now. The entire code needed to generate quizzles -- that is, the code you must place on the calling page -- is:

<cf_quizzle quizzleDSN = "quizzle">

This tells ColdFusion to search for a page called "quizzle.cfm" and then execute that page. The snippet "quizzleDSN = quizzle" is called an attribute. We'll explore how these work in the next section. First, though, you must know where ColdFusion looks for custom tags. First, it searches the current directory -- that is, the directory the calling page is in. If it fails to locate the file here, it looks in a directory called Custom Tags, located directly under the main ColdFusion directory.

This mechanism makes it quite easy to have two levels or types of custom tags. You can create some code that is specific to your page or project. You'll probably want to put such code in the current directory. Other code will be much more generic; in this case you can place it in the Custom Tags directory where it will be available to all applications.

Now let's take a look at the code that's being called as a custom tag: quizzle.cfm.

Quizzle Code
Just as we created a form that did double duty, handling both new entries and edits to the database, our quizzle code will serve two purposes. First, we must display the initial quizzle question, as well as the possible responses. Once this is done, and the user has taken the plunge, we must serve up a chart showing how others have chosen. If the quizzle is fact-based rather than opinion-based, we may also want to provide the correct answer.

quizzle.cfm

<!--   
         Filename: quizzle.cfm
              Date: 9.3.98
       Created by: hal.helms@utaweb.com
          Expects: attributes.quizzleDSN
            Accepts: attributes.tableWidth
                            attributes.tableBGcolor
                            attributes.tableBorderSize
                            attributes.fontColor
                            attributes.fontSize
                            attributes.fontFace
                            attributes.selection 
--->   
<script language="JavaScript">
   function showError(msg) {
      alert(msg);
   }
</script>

<!--- make sure we have essential arguments --->
<cfif not IsDefined("attributes.quizzleDSN")>
   <cfif not IsDefined("session.quizzleDSN")>
      <script>showError("Did not receive DSN for quizzle")</script>
      <cfabort>
   </cfif>
</cfif>

<!--- initialize non-essential arguments --->
<cfparam name="attributes.tableWidth" default="200">
<cfparam name="attributes.tableBGcolor" default="white">
<cfparam name="attributes.tableBorderSize" default="0">
<cfparam name="attributes.selection" default="random">
<cfparam name="attributes.fontColor" default="black">
<cfparam name="attributes.fontSize" default="2">
<cfparam name="attributes.fontFace"
default="arial, helvetica, sanserif">

<!--- If url.mode is not defined, show initial quizzle --->
<cfif not IsDefined("url.mode")>
   <cfinclude template="quizzle1.inc">
<cfelse>
   <cfinclude template="quizzle2.inc">
</cfif>

Let's work through this code to make sure we understand how to make our quizzles behave.

First, we create a small JavaScript function that we will use to alert the user to any errors we discover. Why JavaScript instead of ColdFusion? As wonderful as ColdFusion is, it doesn't interface with certain low-level OS functions, such as creating pop-up windows -- yet.

Next, we want to make sure that we have received all essential arguments once this page is called. It turns out that the only essential argument we have to have is the datasource that points to the Quizzle database. We expect to receive this either as an attributes variable or as a session variable.

What is an attributes variable? Simply one that is provided within a custom tag. As we said, custom tags call other ColdFusion pages. The designers at Allaire want to encourage code reuse and maintainability. To promote this, they allow custom tags to include attributes variables, or put more simply, attributes. These are name/value pairs that go along with the custom tag and provide additional information. In this specific, we are making sure either that the name/value pair "quizzleDSN = [some_DSN]" or that the quizzleDSN was set with a session variable.

In our quizzle case, we can deal with a variety of attributes including table widths, custom background colors, and font details. Your users will greatly thank you if you allow, but do not require, them to customize these selections. Accordingly, we've created default values for all the customizable selections. These work in just the same way as the "getQuizzle" variables that we initialized earlier; they provide a default value while allowing themselves to be overwritten.

Using <cfinclude>s for more reusable and maintainable code
Next, we come to the heart of the quizzle code -- except there's very little there! Instead of making our page hold all the code first to generate the quizzle and then to provide the answer, we've opted to use <cfinclude> tags. The purpose -- as with much that we do -- is to aid in creating more reusable and maintainable code.

We first test to see if a URL variable called "mode" is present. This will be generated when the user submits the answer. The absence of this variable tells us that we should insert the code to generate the quizzle question: so the call to quizzle1.inc. Of course, if the URL is present, then it's time to present the user with the answers. This is handled by the code contained in quizzle2.inc.

Custom tags, in keeping with their function/object-like nature, have their own scope for all variables contained in them. This means that you don't have to worry about whether your custom tag uses a variable of the same name as your calling page. This is not the case with <cfinclude>d files, which share the same variables as the main page. Unlike custom tags, <cfincludes> do not have a separate scope for variables. Make sure you don't accidentally overwrite your main page variables!]

Examining the included files
We'll just touch briefly on the included files, noting anything unusual. Even though they do the bulk of the work, the code is quite plain. Note, though, that this included file itself calls a custom tag to pick an item from a list at random. There is no limit to how many files can be chained together and its use allows code written once to serve in many places.

quizzle1.inc

<cfset session.quizzleDSN = "#attributes.quizzleDSN#">

<!--- selection by date or random? --->
   <cfif attributes.selection is "random">
     <!--- find out how many quizzles there are --->
      <cfquery
         datasource="#attributes.quizzleDSN#"
         name="getIDlist">
         SELECT qID
         FROM Quizzles
      </cfquery>
      <!--- call custom tag to provide a random selection --->   
      <cf_getRandomListItem aList="#ValueList(getIDlist.qID)#">
      <cfset whereClause = "Quizzles.qID = #getRandomListItem#">
   <cfelse> <!--- this means it's not random --->
      <!--- ...or set for date --->
      <cfset whereClause = "Quizzles.qDateStart <= Date()  
         AND Quizzles.qDateStop > Date()">
   </cfif>
   
   <cfquery
      datasource="#attributes.quizzleDSN#"
      name="getQuizzle">
      SELECT *
      FROM Quizzles
      WHERE Quizzles.qID = #getRandomListItem#
   </cfquery>
      
   <!--- How many choices will there be? --->
   <cfif getQuizzle.q1 NEQ "">
      <cfset responseNumber = "1">
   </cfif>
   <cfif getQuizzle.q2 NEQ "">
      <cfset responseNumber = "2">
   </cfif>
   <cfif getQuizzle.q3 NEQ "">
      <cfset responseNumber = "3">
   </cfif>
   <cfif getQuizzle.q4 NEQ "">
      <cfset responseNumber = "4">
   </cfif>
   
<!--- OK - let's display the quizzle --->
   <form 
      action="quizzle.cfm?mode=answer"
      method="POST">
      <cfoutput>
      <table
         width="#attributes.tableWidth#"
         border="#attributes.tableBorderSize#"
         bgcolor="#attributes.tableBGcolor#"
         >
         <tr>
            <td align="center">
               <img 
                  src="images/q-zoneTop.gif" 
                  width=200 
                  height=42 
                  alt="" 
                  border="0">
            </td>
         </tr>
         <tr>
            <td align="center">
               <font size="1">
                  <b>#getQuizzle.qQuestion#</b>
               </font>
            </td>
         </tr>
         <tr>
            <td align="center">
               <font size="1">
               <!--- send off the primary key and number of 
                  responses as hidden fields --->
               <input 
                  type="hidden" 
                  name="qID" 
                  value="#getQuizzle.qID#"
                  >
               <input 
                  type="hidden" 
                  name="responseNumber" 
                  value="#responseNumber#">
               <cfif #responseNumber# GT "0">
                  <input 
                     type="Radio" 
                     name="response" 
                     value="q1"> 
                     #getQuizzle.q1#  
               </cfif>
               <cfif #responseNumber# GT "1">
                  <input 
                     type="Radio" 
                     name="response" 
                     value="q2"> 
                     #getQuizzle.q2#  
               </cfif>
               <cfif #responseNumber# GT "2">
                  <br>
                  <input 
                     type="Radio" 
                     name="response" 
                     value="q3"> 
                     #getQuizzle.q3#  
               </cfif>
               <cfif #responseNumber# GT "3">
                  <input 
                     type="Radio" 
                     name="response" 
                     value="q4"> #getQuizzle.q4#  
               </cfif>
               </font>
            </td>
         </tr>
         <tr>
            <td align="center">
               <input
                  type="image"
                  src="images/submitQzoneSmall.gif"
                  border="0"
                  >
                  <br>
                  <img 
                     src="images/q-zonebottom.gif" <br>
                     width=200 
                     height=18 
                     alt="" 
                     border="0">
            </td>
         </tr>
      </table>
      </form>
   </cfoutput> 

Again, we make use of attributes as a means of customizing generic code. The "selection" attribute is used to determine whether the start and stop dates found in the database are to guide quizzle display, or whether quizzles should be displayed randomly.

Also note that we are setting a session variable called session.quizzleDSN to the same value as attribute.quizzleDSN. The need for this duplication may not be apparent initially. When the main quizzle page is first called, it is done so from a custom tag that has the quizzleDSN included as an attribute. But this page is called again, this time simply by means of the <form> action parameter that recursively calls quizzle.cfm.

We see two uses of the quizzle.cfm page. The first time, it is called as a custom tag. To call any .cfm page as a custom tag, you need only refer to it as <cf_pageName_without_extension>. As a custom tag, it receives the quizzleDSN attribute included in the calling page. Since the next use of this page is as the action parameter of the <form> tag, it will not be passed the quizzleDSN attribute. This presents a problem, as we will have queries that need a datasource. In order to solve this problem before it occurs, we immediately set a session variable to be equal to the attribute variable. Now, while the scope of the session lasts, this will be available to us.

quizzle2.inc

<table 

   border="<cfoutput>#attributes.tableBorderSize#</cfoutput>"    
   width="<cfoutput>#tableWidth#</cfoutput>">
   

   <!--- Get correct response for this question --->
   <cfquery
      datasource="#session.quizzleDSN#"
      name="getInfo">
      SELECT *
      FROM Quizzles
      WHERE qID = #form.qID#
   </cfquery>
   
   <!--- Did user get right answer? --->
   <cfif form.response is #getInfo.qAnswer#>
      <cfset score = "Right">
   <cfelse>
      <cfset score = "Wrong">
   </cfif>
   
   <!--- What exactly IS the right answer? --->
   <cfif getInfo.qAnswer is "q1">
      <cfset rightAnswer = #getInfo.q1#>
   </cfif>
   <cfif getInfo.qAnswer is "q2">
      <cfset rightAnswer = #getInfo.q2#>
   </cfif>
   <cfif getInfo.qAnswer is "q3">
      <cfset rightAnswer = #getInfo.q3#>
   </cfif>
   <cfif getInfo.qAnswer is "q4">
      <cfset rightAnswer = #getInfo.q4#>
   </cfif>
   
   <!--- increment the guessed response --->
   <cfif form.response is "q1">
      <cfset whichResponse = "getInfo.q1Responses">
      <cfset updateField = "q1Responses">
   </cfif>
   
   <cfif form.response is "q2">
      <cfset whichResponse = "getInfo.q2Responses">
      <cfset updateField = "q2Responses">
   </cfif>
   
   <cfif form.response is "q3">
      <cfset whichResponse = "getInfo.q3Responses">
      <cfset updateField = "q3Responses">
   </cfif>
   
   <cfif form.response is "q4">
      <cfset whichResponse = "getInfo.q4Responses">
      <cfset updateField = "q4Responses">
   </cfif>
   
   <cfset updateValue = #IncrementValue(Evaluate(whichResponse))#>
   
   <!--- update the database results --->
   <cfquery datasource="#session.quizzleDSN#" name="updateDB">
      UPDATE Quizzles
      SET #updateField# = #updateValue#
      WHERE qID = #form.qID#
   </cfquery>
   
   <cfquery
      datasource="#session.quizzleDSN#"
      name="getUpdatedInfo">
      SELECT *
      FROM Quizzles
      WHERE qID = #form.qID#
   </cfquery>
   
   <!--- create value list for Java applet --->
   <cfset totalResponses = #getUpdatedInfo.q1Responses# + 
      #getUpdatedInfo.q2Responses# + #getUpdatedInfo.q3Responses# + 
      #getUpdatedInfo.q4Responses#>
   <cfset fList = "#getUpdatedInfo.q1#">
   <cfset vList = #NumberFormat 
      (getUpdatedInfo.q1Responses/totalResponses*100, "99.9")#>
   
   <cfif getUpdatedInfo.q2 is not "">
      <cfset fList = "#ListAppend(fList, getUpdatedInfo.q2)#">
      <cfset vList = #ListAppend(vList, NumberFormat
          (getUpdatedInfo.q2Responses/totalResponses*100, "99.9"))#>
   </cfif>
   
   <cfif getUpdatedInfo.q3 is not "">
      <cfset fList = "#ListAppend(fList, getUpdatedInfo.q3)#">
      <cfset vList = #ListAppend(vList, NumberFormat 
          (getUpdatedInfo.q3Responses/totalResponses*100, "99.9"))#>
   </cfif>
   
   <cfif getUpdatedInfo.q4 is not "">
      <cfset fList = "#ListAppend(fList, getUpdatdedInfo.q4)#">
      <cfset vList = #ListAppend(vList, NumberFormat 
          (getUpdatedInfo.q4Responses/totalResponses*100, "99.9"))#>
   </cfif>
   
   <cfoutput>
      <tr>
         <td>
         <img src="qzone/images/q-zoneTop.gif" width=200 height=42 
            border="0"> <br>
         <font size="1">

            <cfif getInfo.giveCorrectAnswer is "yes">
               <cfif score is "Right">
                  <b>You are correct!</b>

                  <br>

               <cfelse>
                  <b>Sorry!</b>

                  <br>
                  The correct answer is <b>#rightAnswer#</b>

                  <br>

               </cfif>

            </cfif>

            Here's how others answered.<br>
            (Figures shown are percentages)

         </font>
         <center>

         <APPLET
            CODE="BarChart.class" 
            CODEBASE="/classes/CFGraphs/"
            WIDTH="190" 
              HEIGHT="200">
         <PARAM
            NAME="ChartData.Columns" 
            VALUE="Items,Values"> 
         <PARAM
            NAME="ChartData.Items" 
            VALUE="#fList#"> 
         <PARAM
            NAME="ChartData.Values" 
            VALUE="#vList#">
         <param
            name="title"
            value="Updated Results">
         <param
            name="titleFontName"
            value="Arial">
         <param
            name="LegendFontName"
            value="Arial">
         <param
            name="BackgroundColor"
            value="FFFFFF">
         <param
            name="ShowDateTime"
            value="No">
         </APPLET>

      </center>
      </td>
   </tr>
   
   </cfif>
   </cfoutput>
   </font>
</table>

The entire purpose for the code in this include file is to furnish the ColdFusion Java graph applet with the information it needs to display a real-time analysis of responses. Once this information is put into lists, the Java graphlet takes care of displaying the responses to the quizzle.

In some situations, Java may not be appropriate. In this case, you can fudge the Java applet quite easily. You need answer only a couple of questions: What color do you want your bars to be? How wide should they appear when set next to each other? After you've determined that, create four different colored .gif images in your favorite paint program. (For this little exercise, you need neither much experience in creating graphics nor a high-end paint program -- the Windows Paint program will do.) Make the image as wide as you've decided you want your images to be, but make them only 1 pixel high. Then save these as four separate images.

Now when it's time to display the results of the quizzle, you place the images on the page. The width is set; the height will vary dynamically in order to show a proper bar chart for your quizzle. For example, if you have three responses, one at 20%, one at 30% and one at 50%, you could dynamically set your image heights by multiplying the percentages by 3. This would make the first image 60 pixels tall, the second 90 pixels tall, and the final 150 pixels tall. A little experimenting will help you determine a generic algorithm. And so long as you're developing a generic algorithm, why not create it as a custom tag that you can use whenever you want to employ this little Java-less bar chart?

Conclusion
Even in somber times such as our own, the two most read sections of the newspaper continue to be sports and comics. We all hunger for a little relief, a little fun. Quizzles are a small step in this direction. The code required to generate them is, as you have seen, well within the grasp of us ordinary mortals. Yet what response they generate! Put a quizzle on a page, and watch as users immediately gravitate to it.

Published Sep. 18, 2003— Reads 7,760
Copyright © 2003 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
About Hal Helms
Hal Helms is a well-known speaker/writer/strategist on software development issues. He holds training sessions on Java, ColdFusion, and software development processes. He authors a popular monthly newsletter series. For more information, contact him at hal (at) halhelms.com or see his website, www.halhelms.com.

Add Your Feedback

In order to post a comment you need to be registered and logged in.

Register | Sign-in

Reader Feedback: Page 1 of 1

Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021

SYS-CON Featured Whitepapers

ADS BY GOOGLE

Breaking Java News
Chrysler Group's 'It's Halftime in America' Super Bowl Video Earns Second Place in YouTube's Ad Blitz 2012 Contest
U.S. Census Bureau Daily Feature for February 18
U.S. Census Bureau Black History Month Feature for February 18
Following Is a Test Release
President of the Independent Libya Foundation Announces Vision Statement for Libya on the Anniversary of the Libyan Revolution
Former Congressman and Dukes of Hazzard Star Ben Jones Blasts Nascar Decision
CFIA/Amended Allergy Alert: Undeclared Milk in Certain Sweets From the Earth Brand Cakes
Connection Engine Launches Buyer Score to Provide Instant Predictions of Email Subscriber Value Segment Customers by ROI Potential and Identify High Value Customers

ADVERTISE   |   MAGAZINE SUBSCRIPTIONS   |   FREE BREAKING-NEWSLETTERS!   |   SYS-CON.TV   |   BLOG-N-PLAY!   |   WEBCAST   |   EDUCATION   |   RESEARCH

.NET Developer's Journal - .NETDJ   |   ColdFusion Developer's Journal - CFDJ   |   Eclipse Developer's Journal - EDJ   |   Enterprise Open Source Magazine - EOS
Open Web Developer's Journal - OPENWEB   |   iPhone Developer's Journal - iPHONE   |   Virtualization - Virtualization   |   Java Developer's Journal - JDJ   |   Linux.SYS-CON.com
PowerBuilder Developer's Journal - PBDJ   |   SEO / SEM Journal - SJ   |   SOAWorld Magazine - SOAWM   |   IT Solutions Guide - ITSG   |   Symbian Developer's Journal - SDJ
WebLogic Developer's Journal - WLDJ   |   WebSphere Journal - WJ   |   Wireless Business & Technology - WBT   |   XML-Journal - XMLJ   |   Internet Video - iTV
Flex Developer's Journal - Flex   |   AJAXWorld Magazine - AWM   |   Silverlight Developer's Journal - SLDJ   |   PHP.SYS-CON.com   |   Web 2.0 Journal - WEB2
Apache   |   CMS   |   CRM   |   HP   |   Oracle Journal   |   Perl   |   Python   |   Red Hat   |   Ruby on Rails   |   SAP   |   SaaS

SYS-CON MEDIA:   ABOUT US   |   CONTACT US   |   COMPANY NEWS   |   CAREERS   |   SITE MAP
SYS-CON EVENTS:   |  AJAXWorld Conference & Expo  |  iPhone Developer Summit  |  Cloud Computing Conference & Expo  |  SOA World Conference & Expo  |  Virtualization Conference & Expo
INTERNATIONAL SITES:   India  |  U.K.  |  Canada  |  Germany  |  France  |  Australia  |  Italy  |  Spain  |  Netherlands  |  Brazil  |  Belgium
 Terms of Use & Our Privacy Statement     About Newsfeeds / Video Feeds
Copyright ©1994-2008 SYS-CON Publications, Inc. All Rights Reserved. All marks are trademarks of SYS-CON Media.
Reproduction in whole or in part in any form or medium without express written permission of SYS-CON Publications, Inc. is prohibited.
 
close this window