jQuery Demo: Build A ColdFusion Guru
jQuery is just awesome. I have been playing around with it and every thing it does it just wicked cool. Over the weekend, I built this little demo to play around with adding event handlers after the DOM has loaded. This should keep my HTML mark up very clean and "informational" while at the same time allowing me to do some really cool Javascript stuff.
This demo (or rather experiment) was modelled after those children books that let you choose different head / torso / legs for a given character. Mine of course does not line everything up (I am not about to spend weeks looking for the right photos) but you get the idea. I hope no one gets offended by the graphics or heads chosen. I did not do anything on purpose - I just used whatever good pictures I could find and it's all in good fun:
The above has some pretty decent functionality. But, take a look at the HTML here:
<h1>
Build-a-Guru
</h1>
<div id="build-frame">
<div id="head-frame">
<a class="previous">Previous</a>
<a class="next">Next</a>
<div class="option-frame">
<ul>
<li>Head 1</li>
<li>Head 2</li>
<li>Head 3</li>
</ul>
</div>
</div>
<div id="torso-frame">
<a class="previous">Previous</a>
<a class="next">Next</a>
<div class="option-frame">
<ul>
<li>Torso 1</li>
<li>Torso 2</li>
<li>Torso 3</li>
<li>Torso 4</li>
</ul>
</div>
</div>
<div id="leg-frame">
<a class="previous">Previous</a>
<a class="next">Next</a>
<div class="option-frame">
<ul>
<li>Leg 1</li>
<li>Leg 2</li>
<li>Leg 3</li>
<li>Leg 4</li>
</ul>
</div>
</div>
</div>
How simple is that? The CSS and lack of Javascript make it very easy to see how the document is put together. The markup has become very informational and light-weight. Now, once the document is ready, I am using the jQuery notation $( fn{} ) in order to set the Javascript. Here is that Javascript:
// Once, the DOM (Document Object Model) is ready to
// be interacted with, let's go through an initialize
// the main players in this build-a-guru application.
$(
function(){
// Get the segment width. This will be used for
// calculating and animating later on. While each of the
// segments have different heights (depending on the
// frame in which they are used) all segments will line
// up horizontally (same widths).
var intSegmentWidth = $( "div.option-frame:nth(0)" ).width();
// Let's initialize the variaous slide areas.
$( "//ul" ).each(
function( intListIndex ){
var jUL = $( this );
var jLI = jUL.children( "li" );
var jFrame = $( this.parentNode.parentNode );
var strFrameType = jFrame.attr( "id" ).replace( new RegExp( "^([^\\-]+).*$", "gi" ), "$1" );
// Set the width of the parent list. This should
// be equal to the cumulative width of all of the
// child list items.
jUL.css( "width", (jLI.length * intSegmentWidth) );
// Set up the background images for each slide.
jLI.each(
function( intSlideIndex ){
$( this ).css(
"background-image",
"url( './" + strFrameType + "_" + intSlideIndex + ".jpg' )"
);
}
);
// Start each list at a random place. To get this,
// we will select a ranom slide offset and then
// just multiply that by the width of the segments.
jUL.animate(
{
left: -(Math.floor( Math.random() * jLI.length ) * intSegmentWidth)
},
"fast"
);
}
);
// Let's initialize all the "Previous" action links.
// Each of these links needs to be able to move the slide
// to the right if it can.
$( "a.previous" ).bind(
"click",
function( objEvent ){
var jUL = $( this ).find( "../div/ul" );
var intLeft = parseInt( jUL.css( "left" ) );
// Check to see if we can move right.
if (intLeft < 0){
// Move the list right.
jUL.animate(
{
left: Math.min( (intLeft + intSegmentWidth), 0 )
},
"normal"
);
}
}
);
// Let's initialize all the "Next" action links.
// Each of these links needs to be able to move the slide
// to the left if it can.
$( "a.next" ).bind(
"click",
function( objEvent ){
var jUL = $( this ).find( "../div/ul" );
var intLeft = parseInt( jUL.css( "left" ) );
// Check to see if we can move it left.
if (intLeft > -(jUL.width() - intSegmentWidth)){
// Move the list left.
jUL.animate(
{
left: Math.max( (intLeft - intSegmentWidth), -(jUL.width() - intSegmentWidth) )
},
"normal"
);
}
}
);
}
);
As you can see above, the Javascript basically does three main things:
- Set the background of each list item to be the appropriate image and then randomly animates to one of the slides.
- Binds a click event to all the "previous" links.
- Binds a click event to all the "next" links.
jQuery makes hooking all this stuff up super easy! I can't thank the "each()" method enough. The jQuery selectors combined with the each() method makes "bulk" updating a piece of cake.
Now, if you look at the code above, you will see that I get pointers to many jQuery objects. I think jQuery people tend to chain tons of stuff together and call $() on the fly. This is good, but I feel that it makes the code less readable. Plus, why turn the same DOM object into a jQuery object more than once? I like the idea of getting the jQuery object, storing it, and then referencing it multiple times.
Anyway, I just had some fun with this. If you haven't looked into jQuery, you should; it's totally awesome.
Want to use code from this post? Check out the license.
Reader Comments
Code - very cool. I'm using jQuery more and more and it's really seems to be taking off with the ColdFusion community.
Demo - Ben called. He wants his pants back.
Thanks. Yeah, jQuery makes stuff really easy. At first I was having "emotional" issues with using someone else's code to do stuff I "should" be able to do... but once I got over that, I am seeing that jQuery is just so well thought out and easy to use and Powerful!
I long ago got over the use of someone else's code. As long as it does what I need and does it well (and is legally available), I'm all about shortening my development cycle. And, when the code takes so much of the edge off of browser compatibility issues...bonus. :-)
I just started using jQuery after a year or so of using Prototype and I like it. It does pretty much the same stuff - especially since the selectors got added to Prototype, but Jack Slocum's amazing Ext (nee YUI-ext) library is being integrated with jQuery so that's a huge selling point. His JavaScript UI work is pretty damn cool. I'm still learning jQuery, but all things being equal, I think I'll stick with it.
@Rob,
Yeah, the browser compatibility is great. I like knowing that stuff is just gonna work. I also love that I can stack events, for instance, having as many document "Ready" functions as I want. It's too easy, and something like that is something I know I couldn't do elegantly on my own.
@Ben
Yeah, Prototype offered that capability via Event.observe(), but the chainability was a bit different since not all methods returned the same object as appears to happen with jq.
Somehow, the syntax of jQuery just seems easier/more convenient, as well. Writing it just feels smoother to me. I have no idea how to quantify that. It just is. :-)
@Rob,
I know what you mean. It just feels good. And as far as chainability goes... I like it, but I actually think too much chaining hurts the readability. I am leaning more towards getting a jQuery object as a local function variable and then just running multiple commands on it. I think it keeps the lines shorter and makes it easier to format.
But yeah, something smooth about it.
Interesting. I may consider trying to rebuild this in Spry if you don't mind, although as I said in NYC, I tended to avoid the effects junk. :)
@Ray,
That would be cool. It would be great to see it in Spry as a comparison. That Spry demo you gave was really good. If you want, I can email you the graphics, or you can just grab them from the page... although they are background images, so, not sure how easy that is to grab.
@Ray: Or you can finally cave in and start using jQuery. ;o)
I don' t know man - I just like using easy code. ;)
Ben - yeah - shoot me the files please. No rush though.
@Ray
I've never used Spry, but I can't imagine that there's anything easier than jQuery. As I said above...smooth. And so freaking intuitive (for most operations) that it kind of makes me smile just a little when I use it. :-)
Ha ha ha :)
@I was laughing at Rey's comment (FYI)... in case any one thought I was laughing at them :)
I'm very offended. I'm never going to come here again. Or maybe I'll just get over it. ;)
I'd never heard of jQuery before Ben raved about it recently; but I now already find it indispensible - and incredibly easy to pick up!
I've been using it for both front- and back-end interfaces, and after three weeks of using jQuery have found myself answering a load of newbies' questions on the mailing list...
And yes, it's great to write something and know it will work everywhere!
@Seb,
Glad I could help show you something good... there's probably a few jQuery evangelists somewhere right now shedding a tear of joy :)
@Ray: Don't knock it till you try it. I think you're skered that you might fall in love with it like Ben did. ;o)
@Ben: I'm busting out the hankies. :o)
In all fairness to Ray, his Spry demo last week was very impressive. Spry does some very cool AJAX tag stuff that I have not seen anywhere else. This syntax is WAY off (going off memory), but it was something like:
<div spry:mode="loading">AJAX loading....</div>
<div spry:mode="error">Something went wrong!</div>
<div spry:mode="ready">Hey, that was cool!</div>
And it automatically hooks up all that stuff and hides / shows divs as appropriate. I was impressed with that in the same way I was impressed with jQuery's selector expressions.
I don't think this is something that jQuery does or should do. I feel that these are different solutions / problem domains. But you have to admit, that Spry mode stuff is quite cool.
Ben, You are an evil man :-> Very cool. And yet another reason to sart playing with JQuery!
@Pete,
jQuery is awesome on its own... but no reason to not make it a bit more interesting ;)
@All,
If anyone is interested in looking at the full code, you can grab it here:
www.bennadel.com/resources/demo/build_a_guru/build_a_guru.zip
Thats the problem with spry - it's syntax is invalid. By adding additional attributes to HTML tags you are creating markup that is not accessible, not to mention your page won't validate to XHTML Strict.
Good job with jQuery though, it is so good.
Shuns, there _is_ an XMLNS for Spry, which I believe answers the 'attributes don't validate' problem.
@Ray
My bad, didn't know :( However that still means that there will be markup like:
<div spry:mode="loading">AJAX loading....</div>
<div spry:mode="error">Something went wrong!</div>
<div spry:mode="ready">Hey, that was cool!</div>
Which should all be created with Javascript rather than placed in the page, if you are into progressive enhancement / graceful degredation I guess.
Well a lot of people will differ on what "Should" be done. ;)
In my mind, the code you showed is a perfect example of how Spry is easy to use and powerful. That code is FAR simpler than registering event handlers for objects (which you CAN do with Spry if you want). As for degradation - you can use a simple CSS element (class="SpryHiddenRegion") around you greater div and this will completely hide everything inside. Spry knows to remove this during loading.
To fllowup - if you needed to fix a typo in the portion that shows up during loading, I think the Spry example makes it a heck of a lot easier. It's right there. I don't have to hunt up in JS to find it.
I think one thing to remember, and Ray please correct me if I am way off here, but Spry was developed with the tag-coder in mind. The beauty of this Spry tag/mode system is that you don't have to touch any Javascript.
@Ray
I think Spry definately looks easy for say backend interfaces where you know your public, but as far as using CSS to hide the elements - that is something you could do with any framework but doesn't alter the fact that the content will be confusing to screenreaders / search engines.
I agree with Ben, so it is good for someone who wants to get stuff done fast and knows only a little JS if at all.
By the way how big in filesize is the Spry framework?
@Ben - True - but I hate to say that. It is like saying CF was targetted for non-traditional coders. I can code JS. I like that I don't have to (as much) with Spry. To be clear - you _definitely_ need JS when doing more complex Spry work.
@Shuns - Good point.
@Ray: What I'd like to know is if thats just an example of code that's actually used day-to-day or one used used more as a method to intro folks to the capabilities of Spry. If you wanted to have much broader error handling capabilities or use a different Ajax indicator, is that the same syntax or does it become much more verbose? In essence, how much control do you have by using that syntax?
Sorry, By the way how big in filesize is the Spry framework? Anyone know?
Right, I see what you are saying. I guess with Spry, just as with any of these other frameworks, it's not that you can't do the JS, it's more that we now don't have to deal with the boilerplate... less boilerplate, less error, faster coding.
@Shuns: Still big. The team will be doing a 'compressed' version soon.
@Rey - This is how I explain it. It might not be best. I describe Spry as having 3 different Event handlers.
The first event handler type is what you saw Ben demonstrate. Tag based. Super simple. Etc. I can't find the docs now but it supports the 'major' states.
THe second and third types are pure JS, and probably very much like other frameworks. These other two types are tied to either the dataset (so you have stuff like, preload, onload, etc) and the region (so you could run stuff after the region is drawn out for example).
Let me know if that doesn't make sense. (Although I'm heading out for a few hours.)
Thats one of the brilliant things about jQuery compared to other frameworks such as Prototype, Scriptalicious, Yahoo it is only like 19kb
@Ray: Thanks bud. That makes thing clearer.