When generating the resulting list, it would be nice to let the user pick the desired item in a single step without having to click on the item and then find the select button. We'll explore a single-click method.
Finally, when many options are available, it's useful to be able to show which items have already been selected and let the user unselect some and select others as desired.
However, if you want to find keys whose beginning matches a user-supplied string, you can do it without using the "like" function. The following example works just fine as long as you don't have any keys with more than five consecutive "Z"s in them. (You could screen for this on entry or just use more "Z"s.)
<!--- Get Vendors beginning with the search string --->
<cfif isDefined("URL.Vendor") and ("#URL.Vendor#" is not 0)>
<cfset attributes.Vendor="#URL.Vendor#">
<cfelse>
<cfset attributes.Vendor="">
</cfif>
<cfquery name="listVendor" datasource="myDB">
select * from Vendor
where Vendor >= '#attributes.Vendor#'
and Vendor <= '#attributes.Vendor#zzzzz'
</cfquery>
However, suppose you made every selection into a submit button instead of a radio button. Then the user could just click the submit button whose label is the desired key to pick the item with one click instead of two.
<!--- Pick a Vendor from the resulting list ---> <table border="1"> <cfform name="listVendor" action="frmVendor.cfm" method="post"> <tr> <td>PICK</td> <td>VENDOR</td><td>Email</td></tr> <td><input type="submit" name="VendorID" value=0></td><td>(none of these)</td><td> - </td></tr> <cfoutput query="listVendor"> <tr><td><input type="submit" name="VendorID" value="#round(VendorID)#"></td><td>#Vendor#</td><td>#Email#</td></tr> </cfoutput> </cfform> </table>
If this looks too crude, you could put the Vendor name into the submit button instead of the VendorID (assuming the Vendor name is unique).
The previous scripts could go in the same file; I named mine frmListVendor.cfm. They would feed one of two queries; the choice of query depends on whether a useful value was picked by the user. If a Vendor is selected, the query brings back the rest of the row. [Here's an example that returns rows whose Vendor begins with "car": frmListVendor.cfm?Vendor=car.] If a Vendor is not selected, the query brings back an empty row instead.
<cfif isDefined("URL.VendorID") and ("#URL.VendorID#" is not 0)>
<cfset attributes.VendorID="#URL.VendorID#">
<cfelse>
<cfif isDefined ("form.VendorID") and ("#form.VendorID#" is not 0)>
<cfset attributes.VendorID="#form.VendorID#">
<cfelse>
<cfset attributes.VendorID=0>
</cfif>
</cfif>
<cfif attributes.VendorID is not 0>
<cfquery name="qryGetVendor" datasource="myDB">
select * from Vendor
where VendorID = #attributes.VendorID#
</cfquery>
<cfelse>
<cfquery name="qryGetVendor" datasource="myDB">
select * from VendorAdd
</cfquery>
</cfif>
Here's an example of building a list structure from a query. "ListAppend" essentially pastes new values to an existing string and places a comma between the values. In this case, the values are LineIDs already associated with this Vendor.
<cfquery name="getLineVendor" datasource="myDB"> select * from LineVendor where VendorID = #attributes.VendorID# </cfquery> <cfset newLineIDList=''> <cfloop query="getLineVendor"> <cfset newLineIDList=ListAppend(#newLineIDList#, #LineID#)> </cfloop>
Here's the query of possible product lines; the group of lines already associated with the Vendor is a subset of this list. The user will pick from the larger list knowing which lines are already selected (associated with the Vendor) and can select and de-select lines at will.
<cfquery name="getLine" datasource="myDB"> select * from Line </cfquery>
Here's where the query of all Lines and the query of the Lines associated with this Vendor come together. The following code puts a checkbox next to every Line and checks the ones already associated with this Vendor.
It's important to use "listFindNoCase" instead of "contains" or "listContains"; because, the "contains" functions will match pieces of keys. If you use "contains" functions, then if 18 is selected (for example), 1 and 8 will also become checked and will be associated with the Vendor user submits the form; that's not what you want. Use "listFindNoCase" so only complete matches will count.
Finally, the Exit button uses Javascript to break out of the endless loop presented by this form and the page it feeds. It will error out if you don't have an index.cfm in this directory.
<cfform name="frmVendor" action="chgVendor.cfm" method="post"> <table> <tr><td>Vendor:</td> <td><cfinput type="text" name="Vendor" value="#qryGetVendor.Vendor#"></td></tr> <tr><td>E-mail:</td> <td><cfinput type="text" name="Email" value="#qryGetVendor.Email#"></td></tr> <cfoutput query="getLine"> <cfif listFindNoCase(#newLineIDList#, #LineID#)> <cfset qual="CHECKED"> <cfelse> <cfset qual=""> </cfif> <tr><td><input type="checkbox" name="newLineIDList" value="#round(LineID)#" #qual#></td> <td>--#Line#--</td> </cfoutput> <cfoutput> <input type="hidden" name="VendorID" value="#attributes.VendorID#"> <tr><td></td> <td><input type="button" name="dothis" value="Exit" onClick="document.location='index.cfm'; return false;"><input type="reset" name="" value="Reset"><input type="submit" name="formaction" value="Submit"></td><td></td></tr> </cfoutput> </table> </cfform>
All of the scripts presented so far (except for the first two which went into frmListVendor.cfm) can fit into a single file; I called mine frmVendor.cfm. It gives you a list of product line IDs, some of which are associated with the Vendor, and passes along the VendorID to be used. The user can check and uncheck a few options and feed the result to the following set of queries.
These queries update or insert the Vendor, delete all product lines for this Vendor, and then add back all selected product lines for the Vendor. I put them all in a single file: chgVendor.cfm. This file calls the form that called it - frmVendor.cfm - and the cycle continues until the user presses the Exit button.
<cfif isDefined("form.VendorID") and ("#form.VendorID#" is not 0)>
<!--- Update --->
<cfquery name="chgVendor" datasource="myDB">
update Vendor set
<!--- (leave VendorID alone) --->
Vendor = '#trim(form.Vendor)#',
Email = '#trim(form.Email)#'
where VendorID = #form.VendorID#
</cfquery>
<cfset ID1="#form.VendorID#">
<cfelse>
<!--- Make next VendorID and add vendor with it --->
<cfquery name="getMax1" datasource="myDB">
select max(VendorID) as Max1
from Vendor
</cfquery>
<cfif len(getMax1.Max1)>
<cfset ID1=getMax1.Max1+1>
<cfelse>
<cfset ID1=1>
</cfif>
<cfquery name="addVendor" datasource="myDB">
insert into Vendor (VendorID, Vendor, Email)
values (<cfoutput>#ID1#, '#form.Vendor#', '#form.Email#'</cfoutput>)
</cfquery>
</cfif>
<cfif isDefined("form.newLineIDList")>
<!--- Delete all Product Lines for this Vendor --->
<cfquery name="delLineVendor" datasource="myDB">
delete * from LineVendor
where VendorID = #ID1#
</cfquery>
<!--- Insert Selected Lines for this Vendor --->
<cfloop index="ID2" list="#form.newLineIDList#">
<cfquery name="addLineVendor" datasource="myDB">
insert into LineVendor (LineID, VendorID)
values (<cfoutput>#ID2#, #ID1#</cfoutput>)
</cfquery>
</cfloop>
</cfif>
<cfset ref="frmVendor.cfm?VendorID=#ID1#">
<cflocation URL="#ref#">
The techniques for doing these tasks ranged from using inequalities in SQL to using multiple submit buttons in a form to packing a query into a list for later ready reference. =Marty=
[For the demonstration of this tip, the exit point was changed from index.cfm to frmListVendor.cfm, and a sample link was added to demonstrate filtering the list.]