Sunday, May 11, 2008    
Home My Books Blog ColdFusion About Me Back    

Calendar
<< May 2007 >>
S M T W T F S
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    

Search

Categories
 • Adobe (61) [RSS]
 • AdobeMAX06 (45) [RSS]
 • AdobeMAX07 (59) [RSS]
 • AdobeMAX08 (6) [RSS]
 • AIR (95) [RSS]
 • Appearances (103) [RSS]
 • Books (65) [RSS]
 • CFEclipse (14) [RSS]
 • ColdFusion (1078) [RSS]
 • Flash (88) [RSS]
 • Flex (316) [RSS]
 • Jobs (81) [RSS]
 • JRun (12) [RSS]
 • Labs (26) [RSS]
 • LiveCycle (11) [RSS]
 • MAX (141) [RSS]
 • Regular Expressions (12) [RSS]
 • SQL (36) [RSS]
 • Stuff (492) [RSS]
 • Tips (CF Studio) (80) [RSS]
 • Tips (CF) (795) [RSS]
 • Tips (Dreamweaver) (91) [RSS]
 • Tips (Flex Builder) (2) [RSS]
 • Using CF (131) [RSS]
 • Wireless (96) [RSS]

Other BLOGs
 • Ray Camden
 • Tim Buntel
 • Sean Corfield
 • John Dowdell
 • Steven Erat
 • Brandon Purcell
 • Charlie Arehart
 • Full As A Goog

RSS Feeds
 • Feed
 • Subscribe

Join my mailing list and find out about new books and other topics of interest.

Thoughts, ideas, tips, musings, and pontifications (not necessarily in that order) by Ben Forta ...
NOTE: This is my personal blog, and the opinions and statements voiced here are my own.

Viewing By Entry / Main
May 31, 2007

ColdFusion Ajax Tutorial 2: Related Selects

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.

TrackBacks
There are no trackbacks for this entry.

No trackback URL. Trackbacks are only allowed via interactive form.

Comments
Could there be a JSON version of this? (Where it didnt matter which application server returned the data)
# Posted By Mark Ireland | 5/31/07 8:21 PM
Position: Cold Fusion Developer



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
You can also bind to a URL, so bind="url:getStates.cfm" just return the array with this:

<cfoutput>#SerializeJSON(variables.result)#</cfoutput>

And have no other output
# Posted By Sam Farmer | 6/19/07 3:37 PM
Hi Ben,

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..
# Posted By Doug Cain | 7/13/07 1:23 PM
Doug, try invoking those CFCs directly, a straight <cfinvoke> call in a .CFM page. It looks like you are getting a <cfquery> error independent of the Ajax stuff,s o you need to figure that out first.

--- Ben
# Posted By Ben Forta | 7/13/07 1:34 PM
Hi 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.
# Posted By Doug Cain | 7/13/07 2:08 PM
Thanks for the tutorial, I just finished a State / City select chain using it. One problem I am having is with speed. My initial states select box populates very quickly but the query of the cities takes up to 30 seconds. The query itself is very snappy. Any ideas on helping me speed this up?

Thanks so much.
# Posted By Matt F. | 7/15/07 11:50 PM
Matt, try calling the City CFC method yourself, from a <CFINVOKE>, and see how it performs. Then try it also from a URL setting RETURNFORMAT="json", and see how that performs.

--- Ben
# Posted By Ben Forta | 7/16/07 9:42 AM
Hey 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
# Posted By Matt F. | 7/16/07 8:05 PM
When working with this example, I get the following error in the AJAX debug window

"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.
# Posted By Chris | 8/4/07 5:04 PM
I am playing around with my new coldfusion 8 install. I am trying to use your example to bind data from two of my cfc's But for some reason, my tests don't work at all. It does not populate any of the inputs and gives no errors


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>
# Posted By Jeremy Rottman | 8/11/07 6:04 PM
Hello Ben,

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>
# Posted By Scott Terrell | 8/21/07 10:06 AM
I used this and it works great on a test site i got, but when i add it to the site i'm working on my Application.cfc onRequestStart / onRequestEnd cancels it out. any idea why?

<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>
# Posted By K0rrupt | 8/23/07 11:59 PM
I'm having trouble putting this example code up on my server. I keep getting this error: Error invoking CFC /art.cfc: Not Found

Any suggestions on what I'm doing wrong?
# Posted By Kasey Koester | 9/4/07 5:18 PM
Hi! Ben,

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,
# Posted By Jainee | 9/24/07 2:46 PM
Hi Ben,
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.
# Posted By Sharad | 9/28/07 1:55 AM
Instead of sending the selected item from the first select box to the bind of the second select, is there a way of passing the first value as a CFgrid Argument.
# Posted By Michael Brennan-White | 10/8/07 2:00 PM
How would you go about defaulting values to the related selects.

Thanks
# Posted By Scott Terrell | 10/10/07 6:56 PM
Has anyone been able to use the related selects (bound to a cfc) and set a default value (as if editing an existing record)?
# Posted By Scott Terrell | 10/15/07 12:57 PM
Ben and All - As always - thanks for all your help.

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...
# Posted By David Graham | 10/17/07 8:36 PM
Any luck solving the problem of "window:global: Exception thrown and not caught ". I have seen lots of posts for this but no resolutions.

Mike
# Posted By Mike Demahy | 10/22/07 9:42 AM
I put both of these files (form.cfm & art.cfc) into my root folder which I have set up on a flash drive and mapped to using IIS (which has CF installed into it). I tried calling the form.cfm page and get this error:

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!
# Posted By Jason Presley | 11/1/07 6:17 PM
Hi
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.
# Posted By Tony McCormick | 11/11/07 4:41 AM
Ben,
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
# Posted By Jim | 11/16/07 10:18 AM
Jim, I have asked the engineering team to look into this one too. I'll post a response when I hear something useful.

--- Ben
# Posted By Ben Forta | 11/16/07 10:25 AM
Hi 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
# Posted By Tony McCormick | 11/16/07 7:27 PM
I am getting error on 2nd box bind: "Bind failed. Element not found: subcat_key"
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>
# Posted By Ak | 12/11/07 1:29 PM
Ben,

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.
# Posted By Wendy | 12/12/07 2:41 PM
Many people in these threads are getting the error listed below:

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 :-)
# Posted By Jared | 12/18/07 4:04 PM
Hi

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.
# Posted By james | 1/21/08 9:42 AM
Ben,
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
# Posted By Ken Teegardin | 1/22/08 2:24 PM
Hey Ken - I may not be reading you right. But when you submit the form, it should indeed be available as form.whatever. Have you tried cfdumping the form scope to see all the values?
# Posted By Raymond Camden | 1/29/08 4:49 PM
Ben,

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
# Posted By Matt Bennett | 1/30/08 12:25 PM
Try manually inserting a blank record into it inside of your CFC ;-)
# Posted By Jared | 1/30/08 9:47 PM
Hi,

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
# Posted By Matt Bennett | 1/31/08 12:04 PM
Hi Ben,

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})" />
# Posted By Will Swain | 2/27/08 12:39 PM
Do you have an Application.cfc in play? One with an onRequest method?
# Posted By Raymond Camden | 2/27/08 12:45 PM
Will, sounds like it may be the virtual directory bug, which is supposed to be fix in the updater due out shortly.

--- Ben
# Posted By Ben Forta | 2/27/08 12:46 PM
@Ray, yes - have tried commenting it out but no change

@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?
# Posted By Will Swain | 2/27/08 2:33 PM
Hello Ben,

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.
# Posted By Franklin Aizpurua | 3/6/08 11:02 AM
I'm not sure if the "onChange" event is fired when the options inside of a select box are alters (but not the selection changed, but you could try appending @change to the end of each of your bind variables

{country@change}

Thanks might work.
# Posted By Jared Shields | 3/6/08 6:57 PM
Thanks for the idea Jared,

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.
# Posted By Franklin Aizpurua | 3/7/08 9:01 AM
I have adapted this example to work with 3 selects (the 3rd select being dependant on the second).

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.
# Posted By Paul | 3/13/08 6:17 PM
Your bind example works great, but I have one thing that i can't figure out. When you populate a cfselect using a query you have the selected="#FORM.inputName#" to select an option when editing a record. However, when you bind these select boxes I cannot figure out how to get my user's selection to stay selected in the event of a form error - such as other required fields that were left blank and still need to be filled out- or editing a record to reselect their previous selection that has been stored in the database. I am binding two select boxes one with a list of countries and the other with active states/provinces. I tried sending those selections as arguments to the cfc, but that simply limited my returned query only to those single records not allowing them to change their selection. Any help/suggestions to help me figure out how to maintain these user selections would be appreciated.
# Posted By tim | 3/21/08 7:17 PM
Hello all, I found the answer to my problem and decided to share it here.
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>
# Posted By Franklin Aizpurua | 3/25/08 2:16 PM
hi tim,
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.
# Posted By Arowolo M. | 3/29/08 6:04 PM
Hi

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>
# Posted By James | 4/21/08 4:46 PM
# Posted By Arowolo M. | 4/21/08 5:48 PM
Using:
<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
# Posted By elaine | 4/27/08 10:52 PM
Elaine please see this blog entry:

http://www.coldfusionjedi.com/index.cfm/2007/8/7/S...
# Posted By Raymond Camden | 4/28/08 9:23 AM
This post is following a couple different threads. The one that brought me here is the inability to select an option with a bind expression. I solved the issue for my app by setting the bindonload attribute to "no" and initially populate the select options on my own. I've pasted a little bit of code below as an example.

<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>
# Posted By Ken Hobbs | 5/1/08 7:29 PM
Further to Jared's solution to the issue of the error "window:global: Exception thrown and not caught".

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.
# Posted By Dave Boulden | 5/2/08 7:51 AM

  © Copyright 1997-2008 Ben Forta, All Rights Reserved