Many of us have built related select controls, forms with two (or more) drop down <SELECT> controls, where making a change in one control causes the available selections in the related control to change. For example, selecting a category in one control displays category products in a related control, or selecting a state in one control updates a related control with the cities in that state.
These controls are typically implemented using client side JavaScript to process arrays of data embedded in the page itself. Every possible combination and option is embedded in JavaScript in the page, and client side scripts update controls based on selection changes in other controls.
ColdFusion 8's new Ajax functionality makes this kind of interface really easy, without requiring any client-side scripting, and without requiring that all of the data be embedded in the generated page. Rather, <CFSELECT> controls may be bound to ColdFusion Component methods that are asynchronously invoked as needed.
To demonstrate this, here is a complete working example which uses one of the example databases that comes with ColdFusion. First the ColdFusion Component:
<cfcomponent output="false">
<cfset THIS.dsn="cfartgallery">
<!--- Get array of media types --->
<cffunction name="getMedia" access="remote" returnType="array">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<!--- Get data --->
<cfquery name="data" datasource="#THIS.dsn#">
SELECT mediaid, mediatype
FROM media
ORDER BY mediatype
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfset result[i][1]=data.mediaid[i]>
<cfset result[i][2]=data.mediatype[i]>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
<!--- Get art by media type --->
<cffunction name="getArt" access="remote" returnType="array">
<cfargument name="mediaid" type="numeric" required="true">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<!--- Get data --->
<cfquery name="data" datasource="#THIS.dsn#">
SELECT artid, artname
FROM art
WHERE mediaid = #ARGUMENTS.mediaid#
ORDER BY artname
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfset result[i][1]=data.artid[i]>
<cfset result[i][2]=data.artname[i]>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
</cfcomponent>
This CFC contains two methods. getMedia returns all of the media types in the art catalog database, and getArt accepts a media id and returns any art that is associated with that passed id. Both methods convert their results into two dimensional arrays, with the first dimension containing the id (to be used as the value in the <SELECT> control) and the second containing the display text. (For now, this two dimensional array is the format required by <CFSELECT>).
Now for the form itself:
<cfform>
<table>
<tr>
<td>Select Media Type:</td>
<td><cfselect name="mediaid"
bind="cfc:art.getMedia()"
bindonload="true" /></td>
</tr>
<tr>
<td>Select Art:</td>
<td><cfselect name="artid"
bind="cfc:art.getArt({mediaid})" /></td>
</tr>
</table>
</cfform>
The form contains two <CFSELECT> controls, one named "mediaid" and the other named "artid".
"mediaid" is bound to cfc:art.getMedia(), and so to obtain the list of media types to populate the control, the client makes an asynchronous call to the getMedia method in art.cfc, and populates the list with the returned array. As we'd want this control to be automatically populated when the form loads, bindonload is set to "true", this way the getMedia() call is fired automatically at form load time.
"artid" is bound to the getArt method in art.cfc. This method requires that a mediaid be passed to it, and so {mediaid} is used so as to pass the currently selected value of control mediaid (the first <CFSELECT>). Because these two controls are bound together, the second dependant on the first, ColdFusion automatically generates JavaScript code that forces artid to be repopulated with newly retrieved data whenever mediaid changes.
This example binds just two controls, but this mechanism can be used to relate as many controls as needed, and not just <CFSELECT> controls either.
Location: Kansas City, MO
Salary: $70,000/year
Benefits: group health insurance, dental insurance, vision insurance, fitness reimbursement, 401(k) plan, paid vacation and sick time and holidays.
Work hours are generally 9:00 AM - 5:00 PM. Payroll is paid semi-monthly.
Start Date: 06/11/07
Experience:
Two years of experience designing, developing, maintaining and enhancing Internet site content and applications
using Web development tools Macromedia's Dreamweaver or Cold Fusion Studio MX. Must be highly proficient
with HTML, XHTML, JavaScript, CSS. Experience with Cold Fusion server MX. Experience working in a multi-server
environment using development, testing, staging and production servers. Experience using FTP,
VPN, and terminal services clients. Must be experienced with common web browsers, web standards and platform
specific development issues.
General Skills:
Must be self-motivated and able to work with minimal direction.
Work quickly and efficiently.
Excellent analytical skills.
Knowledge of Intel based PC systems.
Excellent verbal and written communication skills.
Technical Skills:
Required skills:
-ColdFusion MX
-SQL Server
-JavaScript
-AJAX
-CSS
-HTML
Desirable skills:
-Cold fusion certified
-Flash MX
-Flex 2.0
-ActionScript
CONTACT INFORMATION:
Ryan Mac Donald
MegaForce LLC
7450 West 130th Street / Suite 300
Overland Park, Kansas 66213
1-800-676-6625 Ext.309
913-402-0800 #309
913-402-8454 - Fax
http://www.megaforceusa.com
rmac@megaforceusa.com
EOE/M/F/H/V
<cfoutput>#SerializeJSON(variables.result)#</cfoutput>
And have no other output
I just tried the bind example out and it fails with:
error:http: Error invoking CFC /art.cfc : Error Executing Database Query.
info:http: HTTP GET /art.cfc?method=getMedia&returnFormat=json&argumentCollection=%7B%7D&_cf_nodebug=true&_cf_nocache=true&_cf_rc=0
info:http: Invoking CFC: /art.cfc , function: getMedia , arguments: {}
in the ajax debugger. It seems to be looking for my cfc in / when both files are in my webroot: /localhost/
This is driving me nuts as I get the same issue trying to bind to a cfc which is in a mapped directory. Hence I went back to your simple example.
This seems like a bug to me? Anyway any thoughts greatly appreciated.
Oh i'm running cf8 on vista 32bit..
--- Ben
Sorry I noticed that , cf8 didn't install the sample stuff it seems. Fixed that by grabbing the cf7 one. I have solved my problem though, I was sending parameters as you would if calling the cfc by url id=1&lang=2 etc when it should be id=1,lang=2.
Doesn't work:
<cfselect bind="cfc:org.survey.api.getChildren(orgid=1&surveyid=2)"
Works:
<cfselect bind="cfc:org.survey.api.getChildren(orgid=1,surveyid=2)"
Simple in the end as ever! Thanks for the quick response.
Thanks so much.
--- Ben
<!--- CFINVOKE --->
<cfinvoke
component="/mydirectory/Loads/act_getZipCode"
method="getOriginCities"
returnVariable="origin_city"
origin_state_id = "1"
>
<cfdump var="#origin_city#">
3532 ms
<!--- URL CALL --->
http://localhost/mydirectory/Loads/act_getZipCode....
36 ms
I used CFINVOKE and it returns the query in 3532 ms and takes about 10-12 seconds to actually fully display the page. I called it from the url using RETURNFORMAT="json" like you suggested and it returned in 36ms... much faster. Does this bring anything to light?
Thanks for your help!
Matt
"window:global: Exception thrown and not caught"
Any ideas? I have stripped everything down to a cfselect that calls a function that I have verified that works. In fact, it's resulset populates in the debug window, but my select isn't populated with it's resultset.
Here is the code I am using
test.cfm
<cfform>
<table>
<tr>
<td>Select Media Type:</td>
<td><cfselect name="catUUID"
bind="cfc:com.UtilityManager.List_Categories()"
bindonload="true" /></td>
</tr>
<tr>
<td>Select Art:</td>
<td><cfselect name="secUUID"
bind="cfc:com.UtilityManager.List_Sections({catUUID})" /></td>
</tr>
</table>
</cfform>
Function: List_Categories
<cffunction name="List_Categories" access="remote" output="false" returntype="array">
<cfquery name="GetCats" datasource="#this.DSN#">
SELECT
fld_category_UUID as catUUID,
fld_category_Name as catName,
fld_category_Alias
FROM
tbl_classAd_Categories
ORDER BY
fld_category_Order ASC
</cfquery>
<cfset catArr = arrayNew(1)>
<cfset i = 1>
<cfloop query="GetCats">
<cfset catArr[i] = structNew()>
<cfset catArr[i].catUUID = GetCats.fld_category_UUID>
<cfset catArr[i].catName = GetCats.fld_category_Name>
<cfset catArr[i].catAlias = GetCats.fld_category_Alias>
<cfset i = i + 1>
</cfloop>
<cfreturn GetCats />
</cffunction>
Function: List_Sections
<cffunction name="List_Sections" access="remote" output="false" returntype="array">
<cfargument name="catUUID" required="yes" type="string" />
<cfquery name="GetSections" datasource="#this.DSN#">
SELECT
fld_section_UUID,
fld_section_Name,
fld_section_Alias,
fld_category_UUID
FROM
tbl_classAd_Sections
WHERE
fld_category_UUID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.catUUID#" />
</cfquery>
<cfset secArr = arrayNew(1)>
<cfset i = 1>
<cfloop query="GetSections">
<cfset secArr[i] = structNew()>
<cfset secArr[i].secUUID = GetSections.fld_section_UUID>
<cfset secArr[i].secName = GetSections.fld_section_Name>
<cfset secArr[i].secAlias = GetSections.fld_section_Alias>
<cfset secArr[i].catUUID = GetSections.fld_category_UUID>
<cfset i = i + 1>
</cfloop>
<cfreturn secArr />
</cffunction>
Thanks for your wonderful example and dedication to CF. I'm trying to get the basic example of related selects to work using CF8 and binding.
I get the following: "exception thrown and not caught" It does not seem to matter if I bind using cfc or url. I can hit the cfc directly via a url and it works fine. Any help would be appreciated.
CFC
<cfcomponent output="no">
<cfset THIS.dsn="axdealer">
<!--- Get array of media types --->
<cffunction name="getMedia" access="remote" returnType="query">
<!--- Define variables --->
<cfset var data="">
<!--- Get data --->
<cfquery name="data" datasource="#THIS.dsn#">
SELECT Country_ID as CountryID, Country_Name as CountryName
FROM Countries
ORDER BY Country_Name
</cfquery>
<!--- And return it --->
<cfreturn data>
</cffunction>
</cfcomponent>
FORM
<cfform>
<table>
<tr>
<td>Select Media Type:</td>
<td><cfselect name="mediaid"
bind="cfc:art.getMedia()"
value="CountryID"
display="CountryName"
bindonload="true" method="remote" /></td>
</tr>
</table>
</cfform>
<cfcomponent output="no">
<cfset THIS.name = "reg.securitycode" />
<cfset THIS.sessionmanagement=true />
<cfset THIS.dsn = "aiya_ca" />
<cffunction name="onRequestStart" returntype="boolean" output="true">
<!--- DIsplay the header.cfm --->
<cfinclude template="../includes/Header.cfm"/>
<cfreturn true />
</cffunction>
<cffunction name="onRequestEnd" returntype="void" output="true">
<!--- Display Footer.cfm --->
<cfinclude template="../includes/Footer.cfm" />
</cffunction>
</cfcomponent>
Any suggestions on what I'm doing wrong?
Thanks for your tutorial. The newly created bound selection boxes work perfect when I browse direct on our intra net but it will not working at all when browse through VPN. Do you ware of the problem? Any advice? I really like the new feature and don't want drop it due to VPN compatible issue.
Thanks,
Thanks for the example...but i have some problem executing it with Fusebox 4.
I use following code in fusebox.init.cfm
<cfset application.tryajax = createObject( 'component', '#REQUEST.cfcPath#.cfcs.testajax' ).init() />
And then in calling page...
<cfform>
<cfselect bindonload="true" bind="application.tryajax.agnt()" name="agent_code" multiple="true" size="4">
</cfselect>
</cfform>
it do not recognise line...
bind="application.tryajax.agnt()"
i tried ...
bind="cfc:tryajax.agnt()"
then it cannot locate tryajax CFC.
Thanks
This may seem simple - but I'm trying to persist the selected values in a form when posting back to the same page. Here's what I have:
(1) HTML SELECT - static values
(2) CFSELECT bound to (1)
(3) CFSELECT bound to (2)
(4) CFSELECT bound to (2)
On repost NONE of the values in 2, 3, or 4 are selected (though they are correct in the FORM). What am I missing? It looks like cfform.persistData and cfselect.selection handle this when using the query attribute...
Mike
error:http: Error invoking CFC /art.cfc : Not Found
info:http: HTTP GET /art.cfc?method=getMedia&returnFormat=json&argumentCollection=%7B%7D&_cf_nodebug=true&_cf_nocache=true&_cf_clientid=1F0E1972D346E48FF8BE4E01B50D62DE&_cf_rc=0
info:http: Invoking CFC: /art.cfc , function: getMedia , arguments: {}
info:LogReader: LogReader initialized
info:global: Logger initialized
If I change the path I get even more of an error. Is there an issue with the / that is showing in front of the art.cfc? Why is this saying that it can't find the cfc.
My local url is: http://localhost/liquidfusiondemo
I have tried binding the cfc to the cfselect in the following ways:
cfc:.getMedia()
cfc:liquidfusiondemo.art.getMedia()
Any help with this path issue would be appriciated!
I got this to work well in HTML forms mainly for Country, State, Town bound dropdowns.
My problem:
How can I get it work in a Flash form - I've tried every combination and thechnique I can think of - it doesnt throw an error, just no results.
I can get it to work with straight drop downs accessing CF queries for each cfselect but I can't get it to work as "bound" fields in a Flash form using a cfc that works in HTML
I'd be grateful for any clues.
Is there an answer for the binding problem that many of us are having in CF 8? Using your simple autocomplete code I get this error:
window:global: Exception thrown and not caught in the ajax cfdebug window
This is the complete ajax cfdebug out which shows that the data is returned but never loaded into the control:
window:global: Exception thrown and not caught (http://pww.partech.com/test/bencode.cfm?cfdebug, line 787)
info:http: CFC invocation response: "Beauty,Blue Moon,Bowl of Flowers"
info:http: HTTP GET /test/art.cfc?method=lookupArt&returnFormat=json&argumentCollection=%7B%22search%22%3A%22B%22%7D&_cf_nodebug=true&_cf_nocache=true&_cf_clientid=5B3D4FB5A704B1B07324B62723A43911&_cf_rc=2
info:http: Invoking CFC: /test/art.cfc , function: lookupArt , arguments: {"search":"B"}
info:widget: Fetching data for autosuggest id: artname , current value: 'B'
Please help. - Jim
--- Ben
Love reading your stuff and this has been most useful.
Will your example work in a Flash form?
How do you get your example to work in a flash form?
I've fiddled with the syntax in cfselect and get nothing - not even errors.
I've not used a lot of Flash but I'm trying to use it to make it harder for hacks and snoops to find the names of variables passed in forms.
Id be most grateful if you could show the changes in cfselect to do this.
Regards
Tony McCormick
I can't figure it out, been trying for an hour now! This is my code:
CFC
<cfcomponent output="false" >
<cfset THIS.dsn="NJDB">
<!--- Get array of media types --->
<cffunction name="getcat" access="remote" returnType="array">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<!--- Get data --->
<cfquery name="data" datasource="#THIS.dsn#">
SELECT cat_key, cat
FROM tb_includes_cat
ORDER BY cat
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfset result[i][1]=data.cat_key[i]>
<cfset result[i][2]=data.cat[i]>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
<!--- Get art by media type --->
<cffunction name="getSubCat" access="remote" returnType="array">
<cfargument name="cat_key" type="numeric" required="true">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<!--- Get data --->
<cfquery name="data" datasource="#THIS.dsn#" >
SELECT subcat_key , subcat
FROM tb_includes_subcat
WHERE cat_key = #ARGUMENTS.cat_key#
ORDER BY subcat
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfset result[i][1]=data.subcat_key[i]>
<cfset result[i][2]=data.subcat[i]>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
</cfcomponent>
cfm
<cfform>
<cfoutput query="data">#subcat# - #subcat_key#</cfoutput>
<table>
<tr>
<td>Select Media Type:</td>
<td><cfselect name="Cat"
bind="cfc:admin.cfc.cat.getCat()"
bindonload="true" /></td>
</tr>
<tr>
<td>Select Art:</td>
<td><cfselect name="subCat"
bind="cfc:admin.cfc.cat.getSubCat({subcat_key})" /></td>
</tr>
</table>
</cfform>
Is there any samples with using the cfselect with more than 2. I haven't been able to get anything more than 2 to work regardless if I use queries, or arrays in the cfc page. Is there some sample I can review that shows three related cfselects working? I've posted this on adobe's cf forums and haven't received any posts. I'm pulling my hair out.
window:global: Exception thrown and not caught (<url>, line 787)
The reason for this is because although you are calling a CFC, your are ultimately sending a full HTTP GET request to the server. In doing so, application.cfm/application.cfc is still being processed. If you are including ANY content via application.cfm/cfc, then your call via AJAX is actually returning the result of the CFC function as well as all content being included in your requests....
The workaround that Im using is to check the value of the CGI.SCRIPT_NAME and if it ends w/ cfc, DONT include any content... that way your CFC is only returing the data that you want returned.
Oh yeah... make sure its in JSON format (SerializeJSON)....
Happy coding :-)
Just to follow up on a topic that I have seen in multiple threads here (and a problem I was having). Trying to get the multiple selects to work, I was getting an error saying that the cfc could not be found. I have all my components and display pages outside of webpages and can invoke all cfcs without a problem, but when it came to trying to get "ajax" to invoke the cfc no luck.
This is very disappointing and I was wondering if there was a reason for this and if this will be changed in subsequent updates?
I have used cfajax from indiankey.com without any problems and will continue to do so as I can not, and frankly don't want to, change the structure of my files.
So for anyone else having problems, for me I had to move all my display and cfc files inside of webpages and then that worked for me.
As always Ben thanks for your continued effort and great work.
I copied the "Using Binding-pg361) example in your book (CF8-getting started) and was able to get it working with no problems. Now I need to do something with the values. I tried passing them using a form submit but that results in an Ajax error.
How do I access the values from my bound listboxes once someone has selected them and submitted the form?
Is there some simple way to use #form.listboxname#?
Ken
I'm trying to add an <option> tag into the code below:
Old:
<table>
<tr>
<td>Select Media Type:</td>
<td><cfselect name="mediaid"
bind="cfc:art.getMedia()"
bindonload="true" /></td>
</tr>
New:
<table>
<tr>
<td>Select Media Type:</td>
<td><cfselect name="mediaid"
bind="cfc:art.getMedia()"
bindonload="true" />
<option value="">---All Media---</option>
</cfselect>
</td>
</tr>
This scenario works great when you populate the cfselect with a query, and allow you to put the option up at the top. When I'm using the cfc and binding, this isn't showing up. Thoughts on how to make this work. Ideally the option tag would be the first option to come up (top).
Thanks! Matt
Just in case anyone wanted the code:
<CFSET sortArray = ArrayNew(1)>
<CFSET QueryAddColumn(data, "sort_order", sortArray)>
<CFSET QueryAddRow(data)>
<CFSET QuerySetCell(data, "MediaType", "")>
<CFSET QuerySetCell(data, "sort_order", 1)>
<CFQUERY NAME="querySorted" DBTYPE="Query">
SELECT * FROM data
ORDER BY sort_order desc, Category asc
</CFQUERY>
<CFRETURN querySorted>
Matt
I'm using your example code and having a problem:
It works fine on my local server cf8 enterprise. Nothing is returned on my production server, cf8 standard. Using Firebug I can see that the call to the cfc is correct, but the response is empty. No error is being thrown. Any suggestions. (BTW, I've had similar problems with binding to a cfgrid too.)
Code:
<cfselect name="operaID"
bind="cfc:#application.cfc_root#perfs.getOperas()"
bindonload="true"></cfselect>
<cfselect name="perfID"
bind="cfc:#application.cfc_root#perfs.getPerfs({operaID})" />
--- Ben
@Ben - ah - is this a known bug then? Is there somewhere I can find more detail about it to check against my scenario? Also, if I bind to a .cfm will I get the same problem?
I'm having trouble when I try to use more than 2 related cfselects.
Now I'm working in a Page with 5 related cfselect for country, state, county, city, street
and because the cfc functions are invoked more than once when you change the country or state for example, the page loads the data very slowly.
When I change the value on the first one, it invokes de cfc function for the other cfselects, but at the same time since the 2nd cfselect is changing it reinvokes again all the cfc functions of the cfselects that are related to him and so on, making the last one call the cfc function for each time the cfselects before him changed
How can I work aroud that?
Here is a example of my cfselects and the way the binds are related
<cfselect name = "country"
required = "Yes"
message = "some text"
query="qCountries"
value ="ID"
display="NAME" >
</cfselect>
<cfselect name = "state"
required = "Yes"
message = "some text"
bindOnLoad="no"
bind="cfc:cfc.getData0025('#dtsource#',{country})">
</cfselect>
<cfselect name = "county"
required = "Yes"
message = "some text"
bindOnLoad="no"
bind="cfc:cfc.getData0035('#dtsource#',{country},{state})" >
</cfselect>
<cfselect name = "city"
required = "Yes"
message = "some text"
bindOnLoad="no"
bind="cfc:cfc.getData0045('#dtsource#',{country},{state},{county})" >
</cfselect>
<cfselect name = "street"
required = "Yes"
message = "some text"
bindOnLoad="no"
bind="cfc:cfc.getData0051('#dtsource#',{country},{state},{county},{city}) >
</cfselect>
The query results are not big so it should be fast if I can avoid calling the cfc functions more times than needed.
{country@change}
Thanks might work.
Unfortunately it doesnt work that way, it seems the "onChange" event is fired and because of that the binds keep calling the cfc.
Any other ideas will be appreciated.
Thanks.
I am wanting to hide the second and third selects when no value has been selected from the first and hide the 3rd select when no value has been selected from the second.
I have been trying to get this working, but cannot find a way to intercept and use the results coming back in the bind i.e. if no results found, hide the relevant select.
Any ideas any one?
Paul.
When i used 2 or more cfselet with related binds the binds called de cfc component for every value that changed.
To avoid that use @none in the bind values, that way only the values without the @none will trigger the bind event, but will send all the variables to the cfc
As an example: the county cfselect need the values from the country and state cfselects, but will only refresh the data when the state cfselect change value
<cfselect name = "county"
required = "Yes"
message = "some text"
bindOnLoad="no"
bind="cfc:cfc.getData0035('#dtsource#',{country@none},{state})" >
</cfselect>
i have been looking for the solution to the problem of bind and selected attributes. after 30 min of search i decide to hack the thing myself.
<!--- function to bind to --->
<cffunction name="ajEmployeeLookUp" access="remote" returntype="array">
<cfargument name="SelectedId" default="0" required="yes" />
<!--- get all the record first --->
<cfquery name="qTemp" datasource="dsn">
SELECT Employee,Name
FROM Employee
</cfquery>
<!--- get the selected rec. using Query of Query --->
<cfquery name="qSel" dbtype="query">
SELECT * FROM qTemp WHERE EmployeeId = #arguments.SelectedId#
</cfquery>
<!--- requery and remove SelectedId from ur ressult --->
<cfquery name="qTemp" dbtype="query">
SELECT * FROM qTemp WHERE EmployeeId <> #arguments.SelectedId#
</cfquery>
<cfset i=1/>
<cfset a=ArrayNew(2) />
<!--- set the selected item first, since thats what the browser will choose first --->
<cfset a[1][1] = qSel.EmployeeId />
<cfset a[1][2] = qSel.Name />
<cfloop query="qTemp" >
<cfset i=i+1 />
<cfset a[i][1] = EmployeeId />
<cfset a[i][2] = Name />
</cfloop>
<cfreturn a />
</cffunction>
<!---- your .cfm page --->
<!--- the selected id can be from a url, form or query. --->
<cfselect name="Employee" bind="cfc:Employee.ajEmployeeLookUp(#selectedid#)" />
that might not be too clean but it does the work.
i will try and work on a better hack.
I wanted to add another way to get the second related drop down to be prepopulated.
Again this is a bit of a hack, but works for now. This is combining something that I read on Raymond Camden's site (http://www.coldfusionjedi.com/) and Ben's example.
Simply put, you use cfajaxproxy to check to see when the first select has loaded and then call some simple Javascript that loops over the options in the select and marks the one that you want as selected.
I'd love for their to be a better way, so if there is please someone educate me :)
<cfajaxproxy bind="cfc:cfc.getClientContacts({contactID.value})" onSuccess="preselected">
<script>
function preselected(){
preSelectedContactID = document.formName.preSelectedContactID.value;
for(var i=0;i<document.formName.contactID.options.length;i++){
if(preSelectedContactID == document.formName.contactID.options[i].value){
document.formName.contactID.options[i].selected = true;
}
}
}
</script>
<cfform name="formName">
<input type="hidden" name="preSelectedContactID" value="#attributes.query.contactID#">
<cfselect name="clientid"
query="attributes.clientlist"
value="clientid"
display="acronym"
selected="#attributes.query.clientID#" />
<cfselect name="contactID" multiple="false" size="1"
bind="cfc:cfc.getClientContacts({clientid})"
bindOnLoad="true"
value="ContactID"
display="lastFirst" />
</cfform>
<cfselect name="mediaid"
bind="cfc:art.getMedia()"
bindonload="true" />
How do you set the initially selected item?
I tried:
<cfselect name="mediaid"
bind="cfc:art.getMedia()"
bindonload="true"
selected="artItem"
/>
But it didn't work. Does selected work with cfselect and bind?
thanks.
elaine
http://www.coldfusionjedi.com/index.cfm/2007/8/7/S...
<cfselect bind="cfc:components.ui.getClientProjectsForSelect({clientID})" bindonload="no" name="projectID" id="projectID" style="width: 200px;">
<cfif Task.taskID eq 0>
<option value="0" selected>No project</option>
<cfelseif Task.taskID gt 0>
<option value="0"<cfif Task.projectID eq 0> selected</cfif>>No project</option>
<cfloop query="ClientProjects">
<option value="#pro_projectid#"<cfif Task.projectID eq pro_projectid> selected</cfif>>#pro_name#</option>
</cfloop>
</cfif>
</cfselect>
His solution worked nicely... in my case I initially put my CFC outside of the directory containg my application.cfm file to avoid the content created by my application.cfm. However I wanted to put the CFC within my application's directory and not have to add extra logic to application.cfm to prevent it from outputting any content when being called by a CFC. Then the answer struck me.
At the start of the method within my CFC that returns the dynamic data to the AJAX call I simply added the following:
<cfcontent type="text/html" reset="yes">
and now it works just fine. The "reset=yes" clears the pre-existing page content without needing to add any logic to your application.cfm/cfc to do the same.
The solution is essentially the same, just a bit less complicated to apply.