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.
Archived Comments
I ended up just doing an ajax call out to a page that would have just the select box on it and the call for the query. That way I could pass in the variable from the one select box and still have my "View All" option. I still wish their was a better way to set it up just using cf8.
You might have tried rolling your own ajaxproxy to populate the select and then added the option with jQuery in the callback function. But I think at this point I'd just switch out the CF ajax for pure jQuery or at the very least just add the item on the server side.
Another option I know that would be easy but I could never get it to work right. Would be to do a Query Add Row with the "View all" option in it.
Josh, instead of QueryAddRow() you would probably have to use a Query of a Query with a SQL UNION statement to append / prepend your static row to the rest of the query.
I believe I have fully copied your example, but I must have done something wrong. I only get the "View All" option, and niether of the states.
Eventually I'd like to get this problem solved: http://www.adobe.com/cfusio... and was directed that this would be a good place to start. Any ideas on why I would not be getting subsequent options?
What does Firebug tell you? Is the Ajax request fired?
Firebug says there's an exception, but I honestly have no idea what to do about it. I don't think the Ajax request is getting fired because AJAX Logger never updates when I change options, and no values for the second cfselect ever show up in the AJAX Logger either.
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/...
Line 103
Ray,
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
Instead of document.ready, try using ajaxOnLoad. See CFML Ref for syntax.
Ray,
That worked great, thanks for the help
Mike
Hi Ray,
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.
I am not sure if this appropriate here but I will try anyways. I am calling a function in a cfc with the returnformat="json" using getJSON. I continue to get an "invalid label" error in Firebug. As a note I am doing the getJSON call to a different subdomain:
jQuery("document").ready( function(){
jQuery.getJSON("https://new.american.edu#request.site.csAppsWebURL#pt_profile/com/utils.cfc?jsoncallback=?", { method: "getProfileData", userID: "rwest" },
function(_data){
// reset the link
});
});
Is your method returning json data?
My function deceleration is:
<cffunction name="getProfileData" access="remote" returntype="struct" returnformat="json">
ok, so if in your callback you do console.dir(_data), do you see what you think you should see?
I think the error is occurring prior to the function call the error. However in firebug under the error is the data structure as I would expect it.
Also, as a note - I am using this same function call in other places successfully.
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.
Before the call? You got me then. Your JS looks VERY slim there so I can't imagine where else it would fail.
Oh wait! I see the issue. More details coming in a sec.
So yes, jQuery lets you make JSONP calls to things on other servers, but this is NOT the same as a JSON call.
A JSONP call is a JSON result with "padding". Please see these two articles and it should help a lot:
http://www.insideria.com/20...
This article talks about JSONP.
http://www.coldfusionjedi.c...
This article demonstrates making a JSONP service in ColdFusion.
Thanks Ray, that makes sense.