Ask a Jedi: Mixing ColdFusion 8 binding with jQuery
Josh asks:
I have been trying to do this for a little while and haven't found any good answers online. Is there any way that you know of to use jQuery to prepend an option to the top of a cfselect that has a bind=some cfc?
I haven't done a lot of mixing of ColdFusion 8 and jQuery, but let's see what we can do with this. First, let's start with the code he tried to use:
var Options = {
"" : "View All"
}
$("#views").change(
function(){
$(this).addOption(Options,true)
})
This looked simple enough, but when I tried to turn it into a full demo, the first thing I ran into was an error. Turns out that 'addOption' isn't core jQuery, but rather a plugin. As a gentle nudge to my readers, or to anyone blogging about jQuery, it may be a good idea to mention when a code sample uses a plugin. In this case, he was using this plugin: ::TexoTela:: jQuery - Select box manipulation. As you can guess, it adds a few new utility methods to drop downs, including the ability to easily add an option. I was then able to generate a complete demo to replicate his issue:
test2.cfm, my main client side file:
<script src="jquery/jquery.js"></script>
<script src="jquery/jquery.selectboxes.js"></script>
<script>
var Options = {
"" : "View All"
}
$(document).ready(function() {
$("#views").change(function(){$(this).addOption(Options,true);});
}
);
</script>
<cfform name="foo">
<cfselect bind="url:test.cfm" id="views" name="views" bindOnLoad="true" display="state" value="id">
</cfselect>
</cfform>
Note the use of binding in the select to test.cfm. Above this is his JavaScript code, bound to the change function. test.cfm isn't too important, but here is the code so you get on the same page:
<cfset q = queryNew("id,state")>
<cfset queryAddRow(q, 2)>
<cfset q["id"][1] = 1>
<cfset q["state"][1] = "Louisiana">
<cfset q["id"][2] = 2>
<cfset q["state"][2] = "Virginia">
<cfset d = serializeJSON(q)>
<cfcontent type="application/json" reset="true"><cfoutput>#d#</cfoutput>
Ok, so what happens when you run this demo? Since his code is bound to the change event, on initial load you see the two states, but if you switch from Louisiana to Virginia, the third option is added. What he really wanted was "When CF8 is done doing it's Ajax crap, run my stuff." Unfortunately, as far as I know, this is not possible. I don't think there is a DOM event for 'something was added to a drop down', and even if there was, we wouldn't want to run on every addition, but only after the last addition.
I tried the ColdFusion 8 ajaxOnLoad function, but this runs immediately after the page loads and before the Ajax call is made.
I went with the assumption that you really wanted to use the bind attribute, and with that, the only way I could see getting this to work was to switch to a bind to a javaScript function. This is what I came up with, and it's not too pretty:
<script src="jquery/jquery.js"></script>
<script src="jquery/jquery.selectboxes.js"></script>
<script>
var d = "";
function getData() {
var result = new Array();
$.ajaxSetup({async:false});
$.getJSON('test.cfm',{}, function(d) {
for(var i=0; i < d.DATA.length; i++) {
var id = d.DATA[i][0];
var label = d.DATA[i][1];
item = new Array();
item[0] = id;
item[1] = label;
result[result.length] = item;
}
} );
//hard coded option
var newitem = new Array();
newitem[0] = "";
newitem[1] = "View All";
result[result.length] = newitem;
return result;
}
</script>
<cfform name="foo">
<cfselect bind="javascript:getData()" id="views" name="views" bindOnLoad="true" display="state" value="id">
</cfselect>
</cfform>
The bind now runs getData. The problem we have here though is that we must return data from this function. To do this, I had to tell jQuery to use synchronous Ajax calls. This is the ajaxSetup call. (As far as I know, this is the only way to do asynchronous calls with the next line.) Next we run getJSON and call our existing script. ColdFusion returns the data within a DATA key, which is a 2D array of items where element 0 is the ID and element 1 is the name. Finally, I added a hard coded option to the end. I could have added this to the front of the array as well.
I don't know about you, but that is a heck of a lot of code. I went ahead and made another demo. This time the assumption was - continue to use test.cfm for our data provider, but get rid of the bind requirement. Ie, do it all jQuery based. Please keep in mind I'm a jQuery newbie, but I think this is a bit nicer:
<script src="jquery/jquery.js"></script>
<script src="jquery/jquery.selectboxes.js"></script>
<script>
var Options = {
"" : "View All"
}
$(document).ready(function() {
$.getJSON('test.cfm', {}, function(d) {
for(var i=0; i<d.DATA.length; i++) {
$("#views").addOption(d.DATA[i][0], d.DATA[i][1]);
}
});
//hard coded option
$("#views").addOption(Options, true);
}
)
</script>
<form name="foo">
<select id="views"></select>
</form>
I've switched from cfform to a simple form and now make use of the select plugin to add each option as I loop over my JSON data. It is also now completely asynchronous which makes me all warm and fuzzy inside.
Comments
Eventually I'd like to get this problem solved: http://www.adobe.com/cfusion/webforums/forum/messa... and was directed that this would be a good place to start. Any ideas on why I would not be getting subsequent options?
Firebug error:
[Exception... "'SyntaxError: parseJSON' when calling method: [nsIDOMEventListener::handleEvent]" nsresult: "0x8057001c (NS_ERROR_XPC_JS_THREW_JS_OBJECT)" location: "JS frame :: chrome://firebug/content/spy.js :: onHTTPSpyReadyStateChange :: line 483" data: no]
http://www.myurl.com/CFIDE/scripts/ajax/package/cf...
Line 103
I have a Cf8 form that has tabs on it. Within one of the tabs i am trying to get the jquey tablesorter() plugin to work. I have this plugin successfully working on all of my other pages, however it does not work when it is within the cflayoutarea. Is there some special syntax in need to use in this situation?
I have tried adding the javascript
$(document).ready(function() { $("#act").tablesorter (); } );
on the main page and in the cflayout tab. neither place works. Also the code for the cflayout area is called with the source attribute on the cflayoutarea tab.
Thanks, Mike
That worked great, thanks for the help
Mike
I had a similar issue where I wanted to prepend a row in my combo options list with "Please select...".
I wasn't bound to using jQuery to solving this - so instead my solution was to use the MS SQL UNION Statement to select a blank row, of the same column select list, before my actual query:
<code>
SELECT 0 AS userID, 'Please select...' AS userForename, ' ' AS userSurname, ' ' AS userEmailAddress
FROM tblUsers
UNION
SELECT userID, userForename, userSurname, userEmailAddress
FROM tblUsers
INNER JOIN tblUserGroupRlnshps ON tblUsers.userID = tblUserGroupRlnshps.userGroupRlnshpsUserID
WHERE tblUsers.userIsEnabled = 1
etc... etc...
</code>
This way - the database is doing all the work and I don't need to manipulate my result set in ColdFusion.
Thanks,
Niall.
jQuery("document").ready( function(){
jQuery.getJSON("https://new.american.edu#request.site.csAppsWebURL...;, { method: "getProfileData", userID: "rwest" },
function(_data){
// reset the link
});
});
<cffunction name="getProfileData" access="remote" returntype="struct" returnformat="json">
The main difference here is that I am using a subdomain (e.g. jQuery.getJSON() call lives on "cms.american.edu" and the URL to the CFC in the getJSON() function is "new.american.edu".
I read online that the getJSON function allows you to make Ajax calls to other domains.
A JSONP call is a JSON result with "padding". Please see these two articles and it should help a lot:
http://www.insideria.com/2009/03/what-in-the-heck-...
This article talks about JSONP.
http://www.coldfusionjedi.com/index.cfm/2009/3/11/...
This article demonstrates making a JSONP service in ColdFusion.
