Selecting Multiple Default Items With ColdFusion 8 Ajax Controls

Posted By : todd sharp Posted At : August 7, 2007 2:26 PM Posted In: Ajax, ColdFusion

8

Ray just blogged about a technique that he and I worked together on to get ColdFusion 8 Ajax controls to have a default selected item. I started posting comments over there and decided to throw together a quick demo here to expand on it a bit. As Ray mentioned we started off building upon Ben's posts.

To add support for selecting multiple items I modifed the JavaScript to accept an array of items. I did have to use a bit of mysteriously undocumented code in this example - namingly the ColdFusion.JSON.decode() function (see this post for more on that).

Here is what the CFC looks like:

<cfcomponent output="false">

<cfset THIS.dsn="cfartgallery">

<!--- 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 mediaid, mediatype
FROM media
ORDER BY mediaid
</cfquery>


<cfreturn data>
</cffunction>

<!--- Get art by media type --->
<cffunction name="getArt" access="remote" returnType="query">
<cfargument name="mediaid" type="numeric" required="true">

<!--- Define variables --->
<cfset var data="">

<!--- Get data --->
<cfquery name="data" datasource="#THIS.dsn#">
SELECT artid, artname
FROM art
WHERE mediaid = #arguments.mediaid#
ORDER BY artname
</cfquery>

<cfreturn data>
</cffunction>

</cfcomponent>

Here's the modified code:

<cfajaxproxy bind="javascript:test({mediaid},'[1,2]' )">
<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>

And the select modified to accomodate:

<cfselect name="mediaid" id="mediaid"
bind="cfc:art.getMedia()" size="4" multiple="true"
bindonload="true" value="mediaid" display="mediatype" />

So this works out - the first select item will now have items 1 and 2 selected by default (note that this is the 'mediaid' that I am passing to the cfc, not the selectedIndex). If you ran this out of the box with the CFC above you'd notice that the bind fails on the second select. This is because - first of all - the argument type is set as numeric. So changing the type to 'any' (or removing the type checking) is the first step. Now in the bind the first select will pass a comma seperated list of selected items to the cfc. Simple enough - just handle that in the query (using an 'in' clause) and voila. The second select will now return ALL art items related to all of the selected media types in the second select. Pretty cool!

Here is the modified getArt function:

<cffunction name="getArt" access="remote" returnType="query">
<cfargument name="mediaid" type="any" required="true">

<!--- Define variables --->
<cfset var data="">

<!--- Get data --->
<cfquery name="data" datasource="#THIS.dsn#">
SELECT artid, artname
FROM art
WHERE mediaid in (#arguments.mediaid#)
ORDER BY artname
</cfquery>

<cfreturn data>
</cffunction>

Comments (8)

Ethan werner's Gravatar I've used both Yahoo! and Gmail. But i've converted to BigString. Check it out.

Here's some info if your interested:
BigString (http://www.bigstring.com), the new free webmail program, offers revolutionary features. When you send mail from your BigString account, you are protected. BigString is like an automatic shredder for your email. You can self-destruct or change an email that's already been sent or read. Don't leave your messages sitting in peoples' inbox forever.

Fred's Gravatar This works for defaulting the first select... How can the 2nd select be defaulted as well?

I tried updating the javascript by adding the same logic to the 2nd select but it doesn't work.

Thanks.

barry.b's Gravatar I'm in the same boat as Fred:

I have 2 related selects (lets stick with the "media" and "art" examples) but I need to pass in previosly selected values as defaults - esp the second "art" cfselect

but how?

Steve Savage's Gravatar I think I've found a simpler solution to this.

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...

Paul's Gravatar Fred and Barry, did you get this issue sorted out? Like you, I want to preselect previously-selected values, not hard-code a preselected value.

Paul's Gravatar I have a category - subcategory setup with this system. I can pre-populate the first select from the database simply by doing the following:

<cfoutput query="Retailer">

<cfajaxproxy bind="javascript:test({category_id},#category_id#)">

...etc...

I've yet to work out how to pre-populate the subcategory drop-down. Help appreciated.

Ray Champagne's Gravatar There is another way to do this, and since these are all hacks of one form or another, I feel like this one is the one that I would choose: http://www.stevenksavage.com/content/500/3.en.cfm

gerald's Gravatar Is there a way to accomplish this with dynamically-generated cfselects? For example:

<cfloop from="1" to="5" index="i">
<cfselect name="dd_#i#" bind="cfc:someCFC.someMethodThatReturnsAQuery()" value="someValue" display="someColumn" />
</cfloop>

After generating the cfselects and submitting the form, the bind statement in my cfajaxproxy says none of the dynamically-generated cfselects were found.

Here's an example of what my cfajaxproxy call looks like:

<cfloop list="#the_list_of_cfselect_names#" index="i">
<cfajaxproxy bind="javascript:test(#i#},#evaluate('form.' & i)#)" />
</cfloop>

Not sure what I could be missing here. Any help is appreciated.