[thelist] CF form problems...

.jeff jeff at members.evolt.org
Sun Jun 2 15:59:01 CDT 2002


daniel,

><><><><><><><><><><><><><><><><><><><><><><><><><><><><><
> From: Daniel Fascia
>
> Im trying to read the input from a set of radio buttons
> in CF for a multiple choice question engine Im making...
>
> for some reason I can <CFOUTPUT> the values (for
> debugging) and they are working fine but I cannot
> evaluate them in <CFIF> or <CFSWITCH> expressions
>
> [snip]
>
> <input type="radio"
>  name="Question_<cfoutput>#page#</cfoutput>"
>  value="1"> Streptococcus pneumoniae<br/>
> <input type="radio"
>  name="Question_<cfoutput>#page#</cfoutput>"
>  value="2"> Haemophilus influenzae<br/>
> <input type="radio"
>  name="Question_<cfoutput>#page#</cfoutput>"
>  value="3"> Legionella pneumophila<br/>
> <input type="radio"
>  name="Question_<cfoutput>#page#</cfoutput>"
>  value="4"> Viral pneumonia<br/><br/>
>
> [snip]
>
> <cfif isDefined("action")>
>   <cfif action IS "check">
>     <cfset answer = "Question_#page#">
>     <cfif answer EQ "1">
>       <b>correct</b>
> 	</cfif>
>   <cfelseif answer IS "2">
>     incorrect
>   </cfif>
> </cfif>
><><><><><><><><><><><><><><><><><><><><><><><><><><><><><

first things first.

the conditional logic in the last section there is incorrect.  i've adjusted
the indenting so you can see which <cfif> block the <cfelseif> tag is being
applied to.  you can see that it's part of the <cfif action IS "check">.
you'll need to move the closing </cfif> just before the <cfelseif> to just
after "incorrect" for it to show "incorrect" if the user doesn't select
answer 1 as their choice.

now, on to the form itself.

you need to set one of the radio buttons to checked by default.  there are a
couple of reasons for this.

 - if the user doesn't select an answer, no value will
   be passed to the processing page
 - some browsers that encounter a group of radio buttons
   will auto-check the first one if there isn't one
   checked.

now that that's taken care of, let's look at the processing and trying to
figure out the value with coldfusion.  first, <cfdump> the form scope to
find out what's being passed to the server -- both form field names and
their values.

<cfdump var="#form#">

now, assuming url.page is 1 and you checked the first radio button, you
should see the following form variables and values:

form.fieldnames = question_1
form.question_1 = 1

that should be what you're expecting.  however, the way you're trying to
access it is causing your problems.  you're assigning the string
"Question_1" to a variable named answer.  then, you're trying to check the
value of the answer variable to see if it's 1 (correct) or something else
(incorrect).  well, since it's value is "Question_1", it'll always indicate
there's an incorrect answer.  the subtle point here is that you're checking
the value of a string, not the value of a form field named "question_1".

some less experienced coldfusion developers will pipe up and say "use the
Evaluate() function".  do yourself a favor -- DON'T.  there's a much more
efficient and readable way to access a form field dynamically like this.

if you're familiar with arrays you know that you access specific elements
within the array using bracket notation.  structures are really just
associative arrays -- ie, they use a string as the index instead of a
number.  so, use bracket notation.

change this:

<cfset answer = "Question_#page#">

to this:

<cfset answer = form["Question_" & page]>

now, your "answer" variable will contain the value of the radio button the
user checked.

now to the conditional logic.  you could use a <cfswitch></cfswitch> block
here, but it'd be overkill as you're only returning 2 possible answers to
the user.  in this instance, a simple <cfif><cfelse></cfif> block will do
nicely.

<cfif answer EQ 1>
  correct
<cfelse>
  incorrect
</cfif>

however, so you know how to use it, here's how the <cfswitch></cfswitch>
block would work.

<cfswitch expression="#answer#">
<cfcase value="1">
  correct
</cfcase>
<cfcase value="2,3,4">
  incorrect
</cfcase>
</cfswitch>

or

<cfswitch expression="#answer#">
<cfcase value="1">
  correct
</cfcase>
<cfdefaultcase>
  incorrect
</cfdefaultcase>
</cfswitch>



now some tips i thought might be helpful.

<tip type="ColdFusion" author=".jeff">

avoid the use of the Evaluate() function at all costs as it makes your code
more difficult to read and makes the server work harder than it has to.  in
most cases where developers find themselves using the Evaluate() function,
they could just as easily use bracket notation.

don't do this:

<cfset myFormVar = Evaluate("form." & myVar)>

do this instead:

<cfset myFormVar = form[myVar]>

the other common use of the Evaluate function is when performing
mathematical calculations -- especially as an attribute value of a
coldfusion tag.

don't do this:

<cfloop from="1" to="#Evaluate(ArrayLen(myArray) - 1)#"

do this instead:

<cfset to = ArrayLen(myArray) - 1>
<cfloop from="1" to="#to#"

or this:

<cfloop from="1" to="#Val(ArrayLen(myArray) - 1)#"

</tip>


<tip type="ColdFusion" author=".jeff">

avoid the use of the IsDefined() function as much as possible as it makes
the code much more difficult to read.  always make sure that every variable
you plan on using is declared before trying to read it or use it in
conditional logic.

</tip>


<tip type="ColdFusion" author=".jeff">

are you concatenating strings and variables to make a larger string?  make
it easier to read in your color-coded editing environment by breaking out of
the string when concatenating variables.

don't do this:

<cfset foo = "bar_#bar#">

do this instead:

<cfset foo = "bar_" & bar>

</tip>


<tip type="ColdFusion" author=".jeff">

save yourself alot of hassle and the coldfusion server additional processing
time -- scope your variables.

</tip>


<tip type="ColdFusion" author=".jeff">

when it comes to using <cfoutput></cfoutput> blocks in your code, some will
argue that using very few or using many is faster than the other and vice
versa.  in the grand scheme of things it doesn't really make a difference.

however, where it *does* make a difference is when trying to work write and
debug code.  having a ton of them will make it alot more difficult to read
compared to having one large one.  here's an example.

hard to read:

<cfloop query="getusers">
  Username: <cfoutput>#username#</cfoutput><br>
  Password: <cfoutput>#password#</cfoutput><br>
  Last Login: <cfoutput>#last_login#</cfoutput><br>
</cfloop>

much easier to read:

<cfoutput>
  <cfloop query="getusers">
    Username: #username#<br>
    Password: #password#<br>
    Last Login: #last_login#<br>
  </cfloop>
</cfoutput>

</tip>


<tip type="Usability/Accessibility" author=".jeff">

too often i see forms where alittle bit of extra effort could have been put
in to make the form easier to use.  do your users a favor, wrap all checkbox
and radio button descriptive text with a <label></label> block.  be sure to
give each checkbox and radio button a unique id and use that unique id in
the "for" attribute of the <label> tag.  this'll increase the clickable area
for that form element saving the user the frustration of trying to click
those 26x26 pixel square targets.

</tip>

.jeff

http://evolt.org/
jeff at members.evolt.org
http://members.evolt.org/jeff/





More information about the thelist mailing list