However, there's another reason you usually use a link instead of a submit button: the value of a submit button is displayed on the face of the button to the user. Admit it; a button bearing a record ID can wind up looking like someone's home or your driver's license emblazoned on your T-shirt. You can do better.
I recently wound up in a situation where page "A", a control page, passes a bunch of form fields to page "B" to cause page "B" to display a list that's limited by these form field parameters. So far, so good.
However, toggling fields in a record and immediately redisplaying the newly changed list is a different proposition. People expect to see where they left off. Deletion is another example of an operation where people expect to come right back and see that the row is really missing from the sliding data window they just left. In either case, you need someplace to keep the query criteria and its starting place, and this is a big chunk of data.
Add and Edit operations are often coded without this consideration. Users spend enough time away from the list that it almost seems reasonable to start over when they get back. However, when there's no delay, you need a better alternative.
Some may say to just use a big query string. However, this invites curious users to see what minor changes will do. Also, the amount of data you can pass this way isn't big and isn't consistent.
Part of the issue is that you have to know which row the user selected. Some may say to make each row a separate form. You can do that, but then you have to repeat all the query criteria in hidden fields again and again for EACH row.
Some may say to put the data into session variables or cookies. However, this can get very confusing if your business model expects a user to have multiple windows open at once. In the case of session variables, it also eats up memory on your server. In the case of cookies, it fails when you least expect it. Cookie storage is limited, and faulty proxy servers make write-once, read-many a more reliable proposition for cookies than write-once, read-once.
Consider a moment what you want to accomplish. You want to pass a bunch of data that pertains to the whole page, and you want to know which row was selected. To do this, simply give the button or image input a name that will submit the form and whose name will tell you which row was involved.
RowID,Code,StatusInd 5,RR,0 12,CC,0 22,SS,1 41,BB,1 83,AA,0 96,QQ,0
First, if the form.Running is defined - it's a hidden field whose purpose is to tell you that the form has been submitted, look for a field name containing TFlip to see if one of these buttons has been pressed. Why name the buttons TFlip{row ID} instead of Flip{row ID}? To avoid confusion in case the word "flip" is embedded in another form field name someday. To look for TFlip, check the submitted form fields. The submitted form fields are in a structure named form. The structKeyList function returns a list consisting of the key names (field names of the submitted form in this case) in the structure. You can find the first item in the list that contains the partial text you're looking for by using the listContainsNoCase function. If the text "TFlip" is found, include flip.cfm to flip the status of the selected row. After flip.cfm is executed, control returns to this point.
<cfif isDefined("form.Running")>
<cfset Hit=listContainsNoCase(structKeyList(form),"TFlip")>
<cfif Hit>
<cfinclude template="flip.cfm">
</cfif>
</cfif>
Run a list query, and begin the form and header for the list.
<cfquery name="statusList" datasource="context"> select * from Flipper order by Code </cfquery> <form method="post"> <table><tr> <td>CODE</td> <td>STATUS</td> </tr>
Loop through rows and end the form. Define the symbol you want to use to represent the row's status in the database. Provide two sets of controls with one commented out. The first set merely uses a submit button whose name is TFlip{row ID}. (The value doesn't matter except for display.) The set that's commented out uses an input tag of type="image" for which you've specified the same name and which specifies a source of your own choosing for the image. (We'll try the image tag later.) After the loop, a hidden tag named Running in the form itself tells the next pass through the page that the form has been submitted.
<cfoutput> <cfloop query="statusList"> <tr> <td>#Code#</td> <cfif StatusInd> <cfset StatusFlag="X"> <cfelse> <cfset StatusFlag="O"> </cfif> <td> <input type="submit" name="TFlip#RowID#" value="$"> <!--- Replace the previous line with this one later <input type="image" name="TFlip#RowID#" src="paw.gif"> ---> #StatusFlag# </td> </tr> </cfloop> <input type="hidden" name="Running" value="Yes"> </cfoutput> </table> </form>
In comments, you'll see an action to remove the last two characters. That's for future use when you try this code again with images. If you create an input of type="image" and name it "Fred", the form structure will contain TWO fields, Fred.X and Fred.Y, each containing a coordinate corresponding to where the user clicked the image. In this case, you only care about a name, so cropping the last two characters makes sense.
The reason for cropping the first five characters is to remove "TFlip". What remains is supposed to be a Row ID. If the name exists but doesn't have a number greater than zero after it, tell the user and stop. Otherwise, what you have left is a candidate row ID.
<cfif not isDefined("Running")>
The form was not submitted; press back button and retry.
<cfabort>
</cfif>
<cfset Hit=listContainsNoCase(structKeyList(form),"TFlip")>
<cfif not Hit>
Action to be taken was not provided; press back button and retry.
<cfabort>
</cfif>
<cfset HitName=listGetAt(structKeyList(form),Hit)>
<!--- ADD next line to use image
<cfset HitName=left(HitName,len(HitName)-2)>
--->
<cfset HitRow=right(HitName,len(HitName)-5)>
<cfif not val(HitRow)>
Row identifier not provided; press back button and retry.
<cfabort>
</cfif>
For this demo, a simple query is used as shown here. If the row ID isn't found, tell the user and stop.
<cfquery name="statusGet" datasource="context"> select StatusInd from Flipper where RowID = #HitRow# </cfquery> <cfif not statusGet.recordcount> The row ID is not in the table; press back button and retry. </cfif>
What's left is easy. Change the status from what it is to the alternative.
<cfquery name="statusSet" datasource="context"> update Flipper <cfif statusGet.StatusInd> set StatusInd = 0 <cfelse> set StatusInd = 1 </cfif> where RowID = #HitRow# </cfquery>
Browse buttons2.cfm. The status should show up as Xs and Os. Click an image to watch its status change. Do the same with buttons.cfm. Both methods work. Both are acceptable. You have just created better buttons and images.
Consider that your typical page has a control that says, in effect, leave this page entirely and return to the main menu. Maybe you used a link to do this in the past. Maybe you used javascript with input type="button". Now you have a better alternative. =Marty=