Posted in ColdFusion | Posted on 08-07-2007 | 12,314 views
So here is an interesting question. Take a look at Ben's post on related selects in ColdFusion 8 (and don't forget it is even easier now). Pretty simple, right? Well how do you set a control to use Ajax and have a default selected item? Turns out this isn't so easy.
The first thing I tried was selected=, figuring that would be the easiest solution, but unfortunately it didn't work.
I then tried ajaxOnLoad, thinking maybe I could set the default myself. But ajaxOnLoad() is fired when the page is complete, but before those Ajax calls to populate the drop downs are done.
I then tried onLoad in the cfform tag. This didn't work at all. So I threw the problem over to Todd Sharp, and together we were able to come up with a solution. It ain't pretty, but it works. My hope is that folks can look at this and suggest something nicer. I'm actually a bit surprised this isn't supported out of the box. It seems like I use forms half the time to edit content, not create content, so being able to set defaults is a must.
Anyway - the code:
2<head>
3<script>
4var imdone = false;
5function test(x,val) {
6 if(!imdone) {
7 var dd = document.getElementById('mediaid');
8 for(var i = 0; i < dd.length; i++){
9 if(dd.options[i].value == val){
10 dd.selectedIndex = i;
11
12 }
13 }
14 imdone = true;
15 }
16}
17</script>
18</head>
19
20<cfform >
21<table>
22 <tr>
23 <td>Select Media Type:</td>
24 <td><cfselect name="mediaid" id="mediaid"
25 bind="cfc:art.getMedia()"
26 bindonload="true" value="mediaid" display="mediatype" /></td>
27 </tr>
28 <tr>
29 <td>Select Art:</td>
30 <td><cfselect name="artid"
31 bind="cfc:art.getArt({mediaid})" value="artid" display="artname" /></td>
32 </tr>
33</table>
34</cfform>
So first off - note the use of cfajaxproxy. It is bound to the first drop down. When the value changes, and this occurs on initial load, code is run to set the default. In this case note the hard coded value of 2. This would be #form.selected# or whatever. Also note the use of a variable to remember that the default value has been selected. The cfajaxproxy will always run on change, so we want to be sure it is run only once.
Thoughts? This code only supports one selected item, and only supports defaulting the left control, but obviously it could be extended to handle both. Again though it is a bit disappointing that essentially one line of code:
had to be extended by about 10 lines of JavaScript. To be fair, my beloved Spry doesn't make this much easier. You can use spry:if type conditionals so it is a bit slimmer. Maybe someone can speak to how other frameworks like Prototype does it?
Edit: A followup post by Todd: Selecting Multiple Default Items With ColdFusion 8 Ajax Controls


<cfajaxproxy bind="javascript:test({mediaid},'[2,3,4]' )">
<script>
var imdone = false;
function test(x,val) {
if(!imdone) {
var dd = document.getElementById('mediaid');
valArr = ColdFusion.JSON.decode(val);
for(var i = 0; i < dd.length; i++){
//loop over the array of selectedItems
for(var j = 0; j < valArr.length; j++){
if(dd.options[i].value == valArr[j]){
dd.options[i].selected = true;
}
}
}
imdone = true;
}
}
</script>
http://cfsilence.com/blog/client/index.cfm/2007/8/...
The docs are here: http://extjs.com/deploy/ext/docs/ for anyone to go through. I looked at them briefly but saw nothing off the top of my head. Will take another look after the kids go down for the night.
I tried updating the javascript by adding the same logic to the 2nd select but it doesn't work.
Thanks.
<pre>
<script>
function initSelect(){
var dd2 = document.getElementById('Model');
for(var i = 0; i < dd2.length; i++){
//loop over the array of selectedItems
if(dd2.options[i].value == '<cfoutput>#form.defaultvalue#</cfoutput>'){
dd2.options[i].selected = true;
}
} ;
}
setTimeout("initSelect()",1000)
</script>
</pre>
I've created a .js file that "overrides" a function from coldfusion's cfajax.js library.
The new version of the function allows you to specify which options are selected as part of the array you return from your "bound" .cfc function.
See my site for details.
http://www.realitystorm.com/experiments/coldfusion...
<cfcomponent>
<cffunction name="get" access="remote">
<cfargument name="TABLE_NAME" default="">
<cfargument name="VARIABLE_NAME" default="">
<!--- this is kind of lame, but cold fusion will not set the selected variable!!!!! --->
<cfargument name="SELECTED" default="" type="String">
<cfset answer=ArrayNew(2)>
<!--- this is to set the "selected" item first; so that they're um.. selected. --->
<cfset iter = 2>
<cfset answer[1][1]=selected>
<cfset answer[1][2]=selected>
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfif ucase(trim(data.value[i])) neq ucase(trim(selected))>
<cfset answer[iter][1]=data.value[i]>
<cfset answer[iter][2]=data.display[i]>
<cfset iter = iter + 1>
<cfelse>
<!--- ooo! we have the label of the first selected value! --->
<cfset answer[1][2]=data.display[i]>
</cfif>
</cfloop>
<cfreturn answer>
</cffunction>
Ray, if you see this comment, how can Steve's solution be passed on to Adobe for possible inclusion in the next update of CF8?
www.adobe.com/go/wish
Can you please give us an example how did you work around with Steve Savage's solution? I'm not sure how to use his new function.
Thanks,
George
I am using the function just for a single cfselect which is using javascript bind.
My example uses a product type/category/sub category hierarchy.
I added an argument to each of the functions in the cfc for the ID of the value I wanted to select:
<!--- Get array of product types --->
<cffunction name="getProductTypes" access="remote" returnType="array">
<cfargument name="typeID" type="numeric">
...
<!--- Get category by product type --->
<cffunction name="getCategories" access="remote" returnType="array">
<cfargument name="typeid" type="numeric" required="true">
<cfargument name="catID" type="numeric">
...
<!--- Get sub category by category --->
<cffunction name="getSubCategories" access="remote" returnType="array">
<cfargument name="categoryID" type="numeric" required="true">
<cfargument name="subCatID" type="numeric">
...
In each of the functions I added a cfif to the query to array loop to set the new array element to true for the passed ID:
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#getTypes.RecordCount#">
<cfset result[i][1]=getTypes.typeID[i]>
<cfset result[i][2]=getTypes.type[i]>
<cfif getTypes.typeID[i] is arguments.typeID>
<cfset result[i][3]=true>
</cfif>
</cfloop>
...
(repeat for categories and sub categories)
Then on the display page I included Steve's magic JavaScript and added the arguments to each of the cfselect tags:
<cfselect name="typeID" bind="cfc:typeCatSubCat.getProductTypes(#typeID#)" bindonload="true" />
...
<cfselect name="catID" bind="cfc:typeCatSubCat.getCategories({typeID},#catID#)" />
...
<cfselect name="subCatID" bind="cfc:typeCatSubCat.getSubCategories({catID},#subCatID#)" />
you have used also Steve script?
or you have made this works only with cfc?
I cannot understand how I can make it works...
this is my code:
<cfcomponent output="false">
<!--- Get array of media types --->
<cffunction name="getRegioni" access="remote" returnType="array" output="no">
<cfargument name="regioneid" type="numeric">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<!--- Get data --->
<cfquery name="data" datasource="#application.dsn#">
SELECT fld_id,fld_provincia,fld_id_regione
FROM tbl_province
ORDER BY fld_id
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfset result[i][1]=data.fld_id[i]>
<cfset result[i][2]=data.fld_provincia[i]>
<cfif data.fld_id[i] is arguments.regioneid>
<cfset result[i][3]=true>
</cfif>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
<!--- Get art by media type --->
<cffunction name="getProvince2" access="remote" returnType="array" output="no">
<cfargument name="regione" type="numeric" required="true">
<cfargument name="provinceid" type="numeric">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<!--- Get data --->
<cfquery name="data" datasource="#application.dsn#">
SELECT fld_id, fld_localita
FROM tbl_localita
WHERE fld_id_provincia = #ARGUMENTS.provinceid#
ORDER BY tbl_localita.fld_localita
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfset result[i][1]=data.fld_id[i]>
<cfset result[i][2]=data.fld_localita[i]>
<cfif data.fld_id[i] is arguments.provinceid>
<cfset result[i][3]=true>
</cfif>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
</cfcomponent>
And this is my form:
<script src="http://www.agriturismoincampania.it/prove/fixColdf...;
<cfform>
<cfselect name="regione" bind="cfc:select2.getRegioni(1)" bindonload="true" id="regione" />
<cfselect name="fld_id_localita" id="fld_id_localita" bind="cfc:select2.getProvince2({regione},20)" />
</cfform>
Where is my error?
bind failed, element not found: regioneid.
Any idea?
I have uploaded my code in:
http://www.agriturismoincampania.it/prove/select2....
and the form
http://www.agriturismoincampania.it/prove/sel.txt
Where is the error? could you help me,please?
I really don't understand where is the error...
I will go crazy!!
http://www.agriturismoincampania.it/prove/sel.cfm
It's possible my error is how I import the javascript fixColdfusionAjax.js?
window:global: Error loading script (http://www.agriturismoincampania.it/prove/fixColdf...=, line 1)
Also, what is fixColdFusionAjax.js?
I've simplified my page....I have red the example in the comment of Chris...
<script src="http://www.agriturismoincampania.it/prove/fixColdf...;
But I think there is another problem, because the second select doesn't retrive any value....
I don't think I will make it work....
error:http: Error invoking CFC /CMS/select2.cfc : The REGIONEID argument passed to the getProvince2 function is not of type numeric.
Probably because if I type http://www.agriturismoincampania.it/select2.cfc?me... it give me the value with true on the selected value....
I need to change my cfc?
Sorry if I stress you with many question but in Italy there aren't many coldfusion's developers...
Finally I made it works....
Thank you for your support...
Two or more....
you call getValues?
Is there any code to show this being implemented?
Any help would be really appreciated.
<cfselect name="courseType" id="courseType" bind="cfc:cfcs.template.getCourseType()" value="courseMethodID" display="courseMethodDescription" bindOnLoad="true" tooltip="Course Type"> <option value="0">Select Type</option></cfselect>
On my initial screen, the option will not show up...first problem.
When the user submits that page back to itself, I need to value they selected to be autoselected on the page again...need a summary page they can change before submiting to db. I tried the JS solution on this page, however, I received an error stating my courseMethodID value was undefined.
<cfajaxproxy bind="javascript:test({courseType},#form.courseType#)">
<script language="javascript">
var imdone = false;
function test(x,val) {
if(!imdone) {
var dd = document.getElementById('courseType');
for(var i = 0; i < dd.length; i++){
if(dd.options[i].value == val){
dd.selectedIndex = i;
}
}
imdone = true;
}
}
</script>
Below is the source of my file where the error is located:
<script type="text/javascript">
_cf_bind_init_1246893138308=function()
{
ColdFusion.Bind.register([['courseType','','change']],{'bindTo':ColdFusion.empty,'bindToAttr':'true','callFunction':'test','bindExpr':[['courseType','','value'],ILT]},ColdFusion.Bind.jsBindHandler,false);
};ColdFusion.Event.registerOnLoad(_cf_bind_init_1246893138308);
</script>
any help would be appreciated
<cfajaxproxy bind="javascript:test({courseType},#form.courseType#)">
it won't work right. Once I figured out I was not using numeric, and switched, it works just fine.
thanks for the code.
I've made this related select, but I have problem with charset. In fact one of my value has accent but I cannot make it formatted properly....
Could someone help me?
This is the link to the component output:
http://www.agriturismoincampania.it/select.cfc?method=getLocalita&provincia=2" target="_blank">http://www.agriturismoincampania.it/select.cfc?met...
And this is on site: http://www.agriturismoincampania.it
What I have to do to make this work? I have tried to put cfheader on utf-8 but nothing change...
http://www.w3schools.com/tags/ref_entities.asp
<cfselect bind="cfc:hotelier.components.GeoInfo.getRegionsByCountry({CountryID})" enabled="No" bindonload="yes" name="RegionID" class="FormFields" id="RegionID" multiple="no" value="RegionID" display="RegionStringEN" selected="#HotelDetails.RegionID#">
<cfoutput> <option value="#HotelDetails.RegionID#" selected="selected">#HotelDetails.REGIONSTRINGEN#</option></cfoutput> ---></cfselect>
For instance, I have two cfselects, a country drop down and a state drop down list bound to the country drop down. I want the selected values from the previous post to the form to be the default selected values... let's see if I can quickly post some code:
<cfform name="f">
Country:<br>
<cfselect id="listCountryCodes" name="listCountryCodes" required="yes" bind="cfc:path.to.my.cfc.that.returns.countries()" bindonload="yes" display="CountryName" value="CountryCode" /><br>
Select State:<br>
<cfselect
id="listStateCodes" name="listStateCodes" required="yes" bind="cfc:path.to.my.cfc.that.returns.states.based.on.Country.Selected(CountryCode={f:listCountryCodes})" bindonload="yes" display="StateName" value="StateCode" />
</cfform>
having two cfajaxproxy tags (both bound to their respective selects) doesn't seem to do the trick. any thoughts based on the above, or do you need more info?
Thanks in advance!
<cfselect name="cbo_status"
bind="cfc:proposal_status_cfc.getStatus()"
bindonload="true"
display="prop_status"
id="prop_status"
/>
<cfselect name="cbo_proposal"
bind="cfc:proposal_status_cfc.getProposal({cbo_status})"
value="prop_number"
size="3"
/>
Then in the cfc: I have a function (getStatus) with a query that "Select distinct prop_status". Then in the function (getProposal), I set cfargument name="var_proposal". This is where I get the "element var_proposal not defined" error. I'd be glad to post the full code, but I didn't want to clog up the blog.
Thanks!!!
i came across the same type issue but a bit confusing! i got 4 select statements!. I am trying to edit the value of the record. So countryid is the one selectbox which is calling no bind operation, it is just listing the countries and countryid is already get populated when we try to edit as it fetches infor from database:
the problem is with the remaining cfselect.. The selects are dependent upon one another!
like the Country >> Province >> Town >> Suburb
Province, town and suburb are using the bind attributes, i want that when my country is selected, it should automatically get the values from the database for the follwing three selects and populate them with the exact info.
code like this:
<tr>
<td align="right"><strong>Country : </strong></td>
<td><select name="countryid" id="countryid" class="inputstyle">
<option value="none">(Select One)...</option>
<cfoutput query="getcountries">
<option value="#countryid#">#country#</option>
</cfoutput>
</select>
</td>
</tr>
<tr>
<td align="right"><strong>Province : </strong></td>
<td><cfselect name="province" bind="cfc:com.remoteCalls.getRemoteProvince({countryid})" bindonload="false" class="inputstyle"><option value="0" selected>Select One</option></cfselect></td>
</tr>
<tr>
<td align="right"><strong>Town : </strong></td>
<td><cfselect name="town" id="town" class="inputstyle" bind="cfc:com.remoteCalls.getRemoteTowns({province})" bindonload="false"><option value="0" selected>Select One</option></cfselect></td>
</tr>
<tr>
<td align="right"><strong>Suburb : </strong></td>
<td><cfselect name="suburb" id="suburb" class="inputstyle" bind="cfc:com.remoteCalls.getRemoteSuburb({town})" bindonload="false"><option value="0" selected>Select One</option></cfselect></td>
</tr>
trouble i am lost where i should use the ajaxproxy to load the contents based upon one after anotehr select box! like the countries selected is ZIMBABWE, so i loaded province,town,suburn based upon each other, so how to make use of ajaxproxy to load the contents based upon one another
I received a empty combo with any example I used it.
this my code
<cfinvoke component="test" method="A_Showhistory_level"
returnvariable="ret_Showhistoryitem" >
</cfinvoke>
<cfdump var="ret_Showhistoryitem" >
<cfform name="OutputHistory">
<table>
<tr><td> Description : </td>
<td> <cfselect name="testbind"
bind="cfc:store.A_Showhistory_level()"
bindonload="true"
>
<option name="blank" >--Select-- </option>
</cfselect>
</td></tr>
</table>
</cfform>
and My component is :
<cfcomponent output="no" >
<cfset datasource = 'Store' >
<cffunction name="A_Showhistory_level" access="remote" returntype="array" >
<cfset a="0" >
<cfquery name="data" datasource="#datasource#" >
Exec sp_showhistoryitem1 '13'
</cfquery>
<!--- <cfdump var="#qShowhistory_level#" >--->
<cfset alevel=arraynew(2) >
<cfloop index="i" from="1" to="#data.RecordCount#">
<cfset result[i][1]=data.cases_location_id[i]>
<cfset result[i][2]=data.boxname[i]>
</cfloop>
<cfreturn result >
</cffunction>
</cfcomponent>
I very apreciate any help with this problem
I copy and paste the error
Webpage error details
User Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; GTB6.5; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Timestamp: Wed, 14 Jul 2010 13:22:49 UTC
Message: Exception thrown and not caught
Line: 803
Char: 1
Code: 0
URI: http://localhost/CFIDE/scripts/ajax/package/cfajax...
<tr><td> Description : </td>
<td> <select name="testbind" id="testbind">
<option name="blank" >--Select-- </option>
</select>
</td></tr>
Any suggestion
/CFIDE/scripts/ajax/package/cfajax.js:803Uncaught SyntaxError: parseJSON
Also I test result from the array and query and I used dump to view the result and averything looks fine.
Also I see on Jedi blog and I comment all query's from application.cfm and rename application.cfc
if you want I have print screen how I sent to you :
Thanks a lot
like send the id and the description along with it?
<!-- 34586154205 --> ["HAZEN TRANSPORT"]
Is there a CF Patch available?
an html comment (with my session id) and that was being returned with my JSON. Ergo, parseJSON error.
I removed the cfoutput from the file being cfincluded and voila, no more parseJSON error.
The Net tab in the firebug debug window was really helpful once I knew what I was looking for.
The XHR tab shows all of the information being passed in ajax including request and response.
The response tab, having expanded the URL shows the information that you are getting back.
[Add Comment] [Subscribe to Comments]