ColdBox 2.6 + AJAX (powered by jQuery) = Sinfully Easy

Posted on May 16, 2008 at 4:48 PM in ColdBox, ColdFusion, jQuery

I've mentioned before that I <3 ColdBox and that I <3 jQuery. Independently of one another, they are just a pleasure to work with. Today I decided to write my first-ever jQuery-powered AJAX functionality inside a ColdBox-powered application. It's ridiculously simple to do - one might even say sinful. So easy in fact, that I decided to post a quick "tutorial" on how to handle a pretty common task with ColdBox and jQuery.

The Task: Browse a User List

Pretty much any decent-size application has a user list. When the list of users gets really big, most people add some sort of functionality to the interface that allows the list to be sorted by the first letter of the last name or sometimes even the first name. It might look something like this:

Sort Users By Alphabet

Typically speaking, when you click on whichever letter you want to sort by, a brand new page will be loaded, and the sorting will be done by passing the letter to the application server in the querystring, then passed on to the database server to retrieve the appropriate records. I like to save bandwidth where I can, so I decided to update an application I'm working on and make use of a little bit of AJAX so that only the actual list is replaced/refreshed, rather than loading an entire page.

ColdBox: noLayout=true

ColdBox's setView() method has an optional argument named "noLayout". By default this argument is set to 'false'. However, for our little AJAX operation, we want to change that to 'true', because we want only our list of names to be rendered, and not the entire layout. (Remember, the layout is already on the screen, along with the default list and the alpha-select list as shown above.)

There are a couple of ways you can have ColdBox take care of this request. One way is to have separate methods; one for rendering the full page (including layout), and one for rendering only the actual list itself. Another possibility is to have a single method that handles the request, and use an "isAjax" flag to decide whether or not to render the whole layout. My personal preference is the latter, because it allows me the luxury of never messing with the HTML in the view once I've got it and the jQuery (shown below) in place. So, here is a snippet of how I handle this flag in my controller.

  1. if ( NOT event.getValue("isAjax", false) ) {
  2. event.setView("nameSelect");
  3. } else {
  4. event.setView("nameSelect", true);
  5. }

The first line determines if 'isAjax' is false, which is set to be the default value. If it is false, then I set the view without providing the "noLayout" argument, which as we noted above defaults to false. However, if 'isAjax' is true, I set the view and supply a value of true to the "noLayout" argument.

That is all that is required! We're now done with the ColdBox half of our update! Schweeeeeet!

jQuery: The Beauty of Unobtrusive JavaScript

For years I shied away from using JavaScript in my applications. There were two things about it that I just absolutely hated:

  1. Mucking up my HTML with JavaScript code
  2. The ease with which a user can disable or otherwise get around it, which would break the application (for that user)

Then I found jQuery. Now I can write a comparatively small bit of code, and I can leave my (x)HTML alone to do what it is supposed to do. Our little alpha-sort list is no different. I'm not going to touch the HTML at all. This way, if the browser does not support JavaScript (or it is disabled), the application still works perfectly fine. However, if JavaScript is supported, we get the bonus of using far less bandwidth and execution time. So, without further ado, here is our quick and dirty jQuery:

  1. $(document).ready(function() {
  2. $("a.select-letter").click(function() {
  3. var theURL = $(this).attr("href")+"&isAjax=1";
  4. var thisL = $(this).attr("class");
  5. var thisL2 = "";
  6. // start the 'loading' image
  7. $("#ajax-load").removeClass("hide");
  8. $("a.select-letter").each(function() {
  9. thisL2 = $(this).attr("class");
  10. if ( thisL2 != thisL ) {
  11. $(this).removeClass("current-letter");
  12. } else {
  13. $(this).addClass("current-letter");
  14. }
  15. });
  16. $.get(theURL, {}, function(data) {
  17. $("#nameSelect").html(data);
  18. });
  19. $("#ajax-load").addClass("hide");
  20. return false;
  21. });
  22. });

Since the purpose of this post is not to teach you the basics of jQuery, I'm merely going to highlight a couple of things that we're doing.

First, on line 3 we're grabbing the URL from the 'href' attribute of the letter that was clicked on, and we are appending our 'isAjax' flag to the querystring, setting it to true (or 1).

Next, on lines 8-15, we're removing the "current-letter" class from all of the letters that were not clicked on, and adding it to the one that the user clicked. (This is a class that highlight's the first letter of the current list. Completely optional, of course, but I like it.)

Then on lines 16-18 we're making use of jQuery's $.get() Ajax method to run our ColdBox event (request) and update the "nameSelect" div with the new list.

Lastly, on line 20, we're telling the browser "hey, don't follow the link you just clicked on", because we've already handled the request via Ajax.

Summary

It's that easy. Sinful. Delightful. I so totally <3 ColdBox + jQuery. :-)

Comments
(Comment Moderation is enabled. Your comment will not appear until approved.)

On 5/16/08 at 6:56 PM, Jason Durham said:

Schweet. I should have taken your words of wisdom long ago. My next project should be starting soon so expect some questions on ColdBox. :)

On 5/16/08 at 9:20 PM, Sana said:

@ Matt, Love your jQuery implementation. Would you like to start a small app covering jQuery beauty with ColdBox.

@Jason you are welcome to ask million question.. just only one million.. LOL

On 5/20/08 at 9:11 AM, Tony Garcia said:

Very nice, Matt. One minor correction, though. In a couple of places, you indicate that the default value of the noLayout attribute is 'true', when in fact it is 'false' (which is why you explicitly had to set it to 'true' in your 'else' condition in the code snippet you showed).
It might have been better if the attribute was 'Layout' instead of 'noLayout', because 'layout="true"' would be more intuitive as the default behavior instead of the double-negative 'noLayout="false"'.

On 5/20/08 at 1:26 PM, Matt Quackenbush said:

@ Jason - You're far too kind. :-)

@ Sana - I'm interested in hearing more about what you have in mind. Shoot me an email and we can discuss your idea(s).

@ Tony - Nice catch. Thank you. Obviously I knew that, but said it backwards. I do that way too often. I updated the post so that it now reads correctly. ;-)

On 7/8/08 at 9:17 PM, Matt Quackenbush said:

Just wanted to add a bit of clarity to the ColdBox controller code. In the post I am showing an if/else statement on the controller (handler). You only need that if you are calling two different view files. If you're going to call the same view file, just use the following:

event.setView("viewName", event.getValue("isAjax", false));

On 3/10/09 at 2:18 PM, Brad Wood said:

@Matt: I have always been using proxies for my Ajax calls, but it appears you are simply calling the event normally. Is this because you are just using the HTML returned from the request and you aren't needing to do any JSON encoding etc. to the result before returning it?

Now I'm wondering if I _shouldn't_ be using the proxy if the result of the event is immediately usable without additional massaging.

I am using jQuery, but not for my ajax calls. I have been using cfajaxproxy for that those.

Thoughts?

On 3/10/09 at 6:53 PM, Matt Quackenbush said:

@ Brad- I'm calling the event as normal for two reasons:

1) I am taking full advantage of ColdBox's event mechanisms, and therefore I have everything available to me just as I would in a synchronous request, and

2) I am using Ajax only if JavaScript is enabled, so the event exists whether or not Ajax is involved. Since I abhor code duplication, I just use a single event to handle two use cases.

In this particular example the return value is simple HTML, but even in cases where I need a JSON response, I still generally use a "normal" event call and use event.renderData(type:"JSON"). Again, for the same reason as #1 above (and sometimes #2).

RE: cfajaxproxy. I know that I'll be considered a blasphemer for this, but I don't use anything from CF that loads JavaScript, period. It is always extremely bloated, and extremely outdated, and quite frankly, I don't believe that it belongs in the Application Server. If I need Ajax functionality, I write it myself. "Write it myself" used to mean write it from the ground up. Thankfully I found jQuery and so it now just means write the little bit I need to write on top of jQuery to get the job done. :-)

Now then, ColdBox now has an ajaxproxy.cfc that you can utilize for your Ajax calls. I don't think it existed at the time I wrote this post, but that's been nearly a year ago, and I've slept since then, so I can't be certain of that. Anyways, I haven't used it myself, but a lot of people are using it with fantastic results, so that might be something you'll want to take a look at.

Sorry for the book response. Hope it helps nonetheless. ;-)

On 3/11/09 at 1:59 AM, Brad Wood said:

@Matt: Thanks for the reply. That helps.

There's something I don't like about having if statemtents in my handlers that make the events have to "know" how their called (isAjax). I like the anonimity that the proxy provides so my events don't have to
care how they are being called. That being said, I also abhor writing anything twice and adding extra layers that don't do anything.
I didn't know about the event.renderData() method yet, so that is kind of cool.

Would you personally ever recommend using the Coldbox Proxy?

On 3/11/09 at 2:10 AM, Matt Quackenbush said:

@ Brad- I totally understand the thought process behind having the controller not know how it's being called, but I personally have no problem with that (in moderation), as the controller is the traffic cop between the model and the view. Therefore, in my opinion, it *has* to have at least some knowledge of how it is being called.

RE: ColdBox Proxy. I can't really "recommend" something that I've not yet personally used, but I certainly have no reason whatsoever to recommend against it. I think it all depends on what the use case is, and the methodologies employed in building one's applications. If one were to build a front-end (UI) heavy application that used lots of Ajax loads, I'd probably be quite inclined to use it. But again, I certainly have no reason to say not to use it. ;-)
CodeBassRadio

Latest Articles

Eventually something really brilliant and witty will appear right here.

Calendar

March 2024
S M T W T F S
« Feb  
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            

Subscribe

Enter a valid email address.

The Obligatory Wish List