Using CF8 Ajax features to solve the 'pick one of thousands' issue (2)

This post is more than 2 years old.

A few days ago I posted a blog entry discussing a method to allow someone to browse thousands of records within a form. The blog entry made use of ColdFusion 8 built-in Ajax technology. I promised a jQuery version and I finally got around to it. (Reminder - I'm still rather new to jQuery so this code does not represent best practice. Well, probably not. If it does, I'm unexpectedly brilliant.)

I knew that jQuery doesn't provide UI widgets out of the box. There is a jQuery UI project (although I'm not sure how far along it is) and about one million UI plugins, but I decided to stick to what came with the default library.

Instead of using a window like I did in the previous demo, I used jQuery's animation support to hide and show a div. This is rather easy. You can use show, hide, and toggle to show or hide any element on the page. So if you remember my form from the previous blog entry, I added a div below it:

<div id="userlist" style="background-color:##3CF;width:500px;"></div>

The color and width were just random picks and aren't really relevant. Since the div is empty it will not show up on initial page load. Next to my user form field, I added new code to activate my user list:

<tr valign="top"> <td>Owner:</td> <td> <input type="hidden" id="useridfk" name="useridfk" value="#form.useridfk#" /> <span id="ownerspan">User 1</span><br/> <a href="" onClick="toggleSelector();return false">Select Owner</a> </td> </tr>

Note the toggleSelector code. This runs:

function toggleSelector() { $("##userlist").toggle("fast",loadUsers); }

This code gets the userlist div (the double # is due to the code being within a cfoutput) and runs toggle on it. Fast is the speed and loadUsers is a function to run when the toggle is done. Let's look at loadUsers:

function loadUsers() { // if(!$('##userlist').is(':visible')) return; console.log('im on, so going to load stuff'); $('##userlist').load('test_userlist2.cfm'); }

Now I ran into my first problem. I want to load content into div when it is shown. While jQuery makes it easy to show or hide a div, it does not, as far as I know, provide an easy way to tell if the div is currently visible. That seems a bit silly, but after some Googling, I found the URL referenced in the code above and used that for my check. If we aren't showing the div, we just leave. I could have used a JavaScript variable as well I guess. If the div is visible, then we need to load my list of users. I love how simple jQuery makes it.

Ok, so this was almost perfect. The next issue I ran into involved the initial state of the div. Remember how I said it was essentially hidden because nothing was in the div? While it may not have shown anything, it was not actually hidden. The first time you click the link and toggle() is run, it will hide the div. I wanted the first click to show the user list. I used the following code to hide the div on page load:

$(document).ready(function() { $("##userlist").hide() });

Alright - the next thing I need to do is work on my user list. In the previous example I used ajaxLink for my next/previous links. This kept the content within the cfwindow. Obviously I'm not using a cfwindow now, so what can I do? I decided to simply use the same .load function I demonstrated earlier. Let's look at the complete test_userlist2.cfm:

<cfparam name="url.start" default="1"> <cfset total = 92> <cfset perpage = 10>

<script> selectUser = function(id,label) { $("#ownerspan").html(label); $("#useridfk").val(id); $('#userlist').toggle('fast'); }

load = function(url) { $('#userlist').load(url); } </script>

<h3>Select User</h3>

<cfloop index="x" from="#url.start#" to="#min(url.start+perpage-1, total)#"> <cfoutput> <a href="" onClick="selectUser(#x#,'Record #x#');return false;">Record #x#</a><br /> </cfoutput> </cfloop>

<cfoutput> <cfif url.start gt 1> <a href="" onClick="load('#cgi.script_name#?start=#url.start-perpage#');return false;">Previous</a> <cfelse> Previous </cfif> / <cfif (url.start+perpage-1) lt total> <a href="" onClick="load('#cgi.script_name#?start=#url.start+perpage#');return false;">Next</a> <cfelse> Next </cfif> </cfoutput>

If you scroll to the bottom of the code, you can see I'm calling a new load() function (I used the same name as the jQuery function, which may be bad) with the URL I want to load into div. My load function just runs the jQuery version, and with that, my pagination is complete.

The code I use when you select a user is a bit simpler than the CF8 version. I use html() to set the user's name in the span. I set val() to set the hidden form field variable, and then I toggle to div to hide it away.

All in all, I think the CF8 version was a bit simpler to use, especially in the simple 'show/hide' part of the application. I spent 80% of my dev time on this just trying to solve the problem of "is the div showing" which is a bit surprising. I also performed a YSlow comparison. I know folks complain from time to time about the download impact of CF8 Ajax stuff. In my opinion, it really isn't that big of a deal, especially when you consider the ease of use, but I did want to take a look and compare.

The CF8 version, when cached, 12.7K. The jQuery version, when cached, was 10.5K. Not different enough to be significant in my opinion. The non cached version though was hugely different. The jQuery version 66.3K. The CF8 version was 462.5K. As I said - significant. Of course, that's just your first hit, and probably not that much different than a typical Flex application.

The code I used for this demo is attached to the blog entry.

Download attached file.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA

Archived Comments

Comment 1 by Francois Levesque posted on 12/31/2008 at 9:17 PM

Were you using the packed version of jQuery? It should only be about 30k, which is even smaller!

I like how you compare both libraries. I agree that the CF8 ajaxy stuff is a little easier to use, but imo you have so much more flexibility with jQuery. Now, if only they could get done with the jQuery UI project...

Comment 2 by Raymond Camden posted on 12/31/2008 at 9:18 PM

Nope, wasn't using the packed version.

Comment 3 by Craig Kaminsky posted on 12/31/2008 at 9:20 PM

One thing with the footprint comparison is that because you did not use the jQuery UI library, the numbers are a little skewed in jQuery's favor. When one includes all jQuery UI libraries, in it's packed format, the UI library adds 92KB to the footprint. It's still a pretty big footprint swing in favor of jQuery -- CF8: 462KB to jQuery w/ UI: 158KB.

While you don't need to include the entirety of the UI library and can pick and choose the ui actions and visual effects you want included in your project, I found that in two larger projects, I ended up including everything because I so many of the UI features and found I needed to account for that 92KB in the footprint.

The jQuery UI project is well established and now at version 1.5 (1.5.3 to be exact with 1.6 in the RC stage). I have not had any issues with it (effects are super-easy to implement, etc.) and I really like the ThemeRoller feature on the UI site. It let's me quickly get some decent-looking elements in place when reviewing early stages of Ajax work. (

Comment 4 by Raymond Camden posted on 12/31/2008 at 9:21 PM

Odd, I downloaded the packed version, and YSlow shows 41.6K for uncached, which IS better, but the cached version is the same size, 41.6k. It's like the packed version can't be cached.

Comment 5 by Francois Levesque posted on 12/31/2008 at 9:26 PM

That's odd... maybe the cache is full? I don't see why your browser wouldn't cache it unless you have a nocache flag, which I doubt you have ;).

Comment 6 by Raymond Camden posted on 12/31/2008 at 9:29 PM

Firefox is set to not cache, but yes, I'm not using nocache in meta or headers. Maybe the 'de-pack' part impacts the ability to cache.