New Spry Enhancements 4 comments   |   Tags: Spry   JavaScript   |   Sorta-Perma-Link

Even though I've pretty much given up on Adobe's Spry Framework, I noticed yesterday that some major updates have been added in, primary among them the introduction of Spry UI.  According to the Spry Team's blog post, Spry UI is a new way of approaching Spry widgets that moves away from the previous (and kind of annoying) necessity of following a prescribed markup model and now attempts to work with user-defined patterns.  This *should* allow for much more flexibility and customizability, and allow for much more robust opportunities for skinning that were previously possible.  Moreover, because all the widgets will now inherit from the same shared base classes, the door is widened for Spry to become a much more robust framework in the future.

Does the introduction of Spry UI mean that Spry development is alive and well, and that Adobe is committed to making something of it long term?  Only time will tell. 

The problem for me, of course, is that time is precisely the problem.  Development of the framework has been seemingly eternal, and significant updates (whether features or simply information about ongoing development) are VERY infrequent.  While I see a lot of promise in what Spry can do (and can become), "facts on the ground" force me to use other, more mature frameworks for serious development.  

I don't mean this as a slight to Spry, nor to the talented Spry team (or even the thousands of developers who make really good use of it).  The bottom line for me is that I need a framework today that has the fully formed features of a jQuery or Ext.  If Spry Framework is in that position tomorrow, I'll more than happily give it a another chance.

Using Spry Data with Thickbox 0 comments   |   Tags: Spry   jQuery   Thickbox   |   Sorta-Perma-Link
If you've ever tried to use Spry data sets with a default implementation of Thickbox (a jQuery-based version of the familiar Lightbox), you've probably noticed that it doesn't work.

The reason for this, of course, is simple: out of the gates, thickbox.js fires off an initialization function (tb_init) through jQuery's ready().  What this means, technically, is that thickbox has already started its processing and element fishing before Spry's data sets have been fully loaded and rendered.  What this means, practically, is that Thickbox won't work.

Though frustrating, there is a fairly simple way to work around this.  

Conceptually, what we'll be doing is to bypass jQuery's ready() function and load tb_init manually AFTER we know Spry's data sets have fully loaded and rendered.

First, we need to figure out when the data sets are done processing.  This is pretty simple, because Spry comes with a handy way of sniffing this out.

We'll start by setting up a new data region observer.  Our observer will watch the data set and when it reaches the "state" that we define, we can manually fire the thickbox.js processing.

So here's our new observer:

the_Observer= new Object()
the_Observer.onPostUpdate = function() {
   // Here's where the thickbox function call will go...    
};


Spry.Data.Region.addObserver("the_region", the_Observer);

Nothing too complicated here.  We create a new Spry region observer, tell it to watch for the "onPostUpdate" state, and then we can load in whatever processing we want to the function we've defined for that state.

The next step, then, is to load in the thickbox initialization function.

To do this, start by going to the thickbox.js file.  Copy the following lines:

tb_init('a.thickbox, area.thickbox, input.thickbox');
imgLoader = new Image();// preload image
imgLoader.src = tb_pathToImage;


Once you have them copied, go ahead and comment out the entire $(document).ready function, including the lines you just copied.  Save and close.

Go back to your other page and paste the three lines into our observer function.  The final result will look something like this:

the_Observer= new Object()
the_Observer.onPostUpdate = function() {
    // See?  Here's the init function for thickbox...
    tb_init('a.thickbox, area.thickbox, input.thickbox');
     imgLoader = new Image();// preload image
     imgLoader.src = tb_pathToImage;
};

Spry.Data.Region.addObserver("products", the_Observer);


That's all there is to it.  Now your Thickbox content should work correctly.
Checking if Spry eventListener Exists 0 comments   |   Tags: Spry   eventListeners   |   Sorta-Perma-Link

So if you use Spry, you know that adding an eventListener to anything is super-simple.  It's easy to add, and managing the processing that occurs on events is pretty intuitive. 

For example:

Spry.Utils.addEventListener("myButton","click",doMyFunction,false);

This one line of code adds an eventListener to the element "myButton" for the onclick event, which will fire "doMyFunction()".  And it's just as easy to remove the same eventListener:

Spry.Utils.removeEventListener("myButton","click",doMyFunction,false);


Easy enough.  However, I recently found myself wanting to not only add and remove eventListeners, but also to check if they exist for certain elements.  Luckily, before digging into the DOM to much, I checked SpryDOMUtils.js--sure enough, there's a function already built for this.

In fact, as you may or may not be aware, you can run Spry.Utils.addEventListener() on an element as many times as you like--only one eventListener will be registered.  This is because addEventListener() runs a check to see if the eventListener is already registered, and proceeds from there (look at line 166 in SpryDOMUtils.js v. 0.6 to see this in action).

So checking to see if an eventListener is registered for an element is exactly the same as adding and removing the eventListener.  Here's what it looks like:

Spry.Utils.eventListenerIsBoundToElement("myButton,"click",doMyFunction,false);

This will return true or false, and you can do whatever you'd like from there. 

Manipulating Spry Datasets in the DOM 0 comments   |   Tags: Spry   DOM   |   Sorta-Perma-Link

I recently created a little peice of functionality using Spry data to setup two lists that can swap data on the fly,

without the need for any postbacks to the server.  I've done this thing several times before, but in the past, I've done it very inefficiently.  Let me give you an example.

Let's say I'm building a list of songs to put on my mp3 player.  I start with a list of all the songs from my media library, as well as a blank list that's waiting to be filled up with songs for the play list. In the past, what I've done is create two Spry data connections to a database, one to manage the play list, and one to manage the full list of songs.

Of course, this is easy enough to do, but I wanted to make it a bit better.  For example, when selecting a song, I wanted to be able to show that the song was selected (and also make it un-selectable again).  

My past approach would have been to start with an onclick event to handle the data saving.  Once this process was complete, I would have fired a complete reload of both my datasets--when they would reload, the song I added would appear in the play list and the song I selected would now be flagged with a "IN_PLAYLIST" tag that would instruct whatever event listeners I had set up to ignore this until it was removed from the play list.

So this works, but it's horribly inefficient.  First, and most glaring, is that two full rounds to the server are made for every 1 song that is added to the playlist (or removed).  Second, and related, is that this does not take advanatage of easy DOM manipulation of these elements that could have saved some server round trips.  Third, it's just not very elegant, and makes the whole experience feel a bit disjointed.

Not satisified with this, I decided to really dig into doing this better when a similar bit of application work came around.I started by eliminating one of the server requests.  Since I'm going to do this without reloading the dataset from the database, I can load the "playlist" dataset without Spry and do it all on server.  Easy enough.  

So now I'm down to one dataset for my "current library".  In the code, I'm passing some information from my query about each song in the "current library," and each song that is in the playlist is marked with a boolean in a column labeled "IN_PLAYLIST".  In my HTML, I'm using a spry:if to evaluate this column, which determines what kind of image shows up next to the song (e.g., whether or not it is selectable).

From here, I'm using some standard JS to transfer all the details of the selected song to the playlist dataset.  Additionally, I'm using JS to manipulate the "selected" element so that it is no longer selected AND gives an indication that it is somehow different from the rest of the "current library" in that it is "in" the playlist dataset. Again, easy enough.

It's at right about this time that I run smack into a huge problem.  You see, all this time I've been using a Spry dataset for the "current library" songs, but I've also been paging these using SpryPagedView.js.  For some reason, even after modifying the newly selected elements through JS, if I navigate between the pages of the paged view dataset, all of the changes I make (well, at least those that are related to the spry:if) are reverted to their original form (e.g., what they looked like when I initially loaded the page).  So what's happening?  
Well, first of all, I apologize if I don't get this 100% right in my explanation, but you'll see how my understanding eventually led to a solution.

When a paged view dataset is created, all of the initial data elements are stored in various arrays.  When you navigate between pages, Spry evaluates each 'page' based on a few variables (page size, page number, etc) and uses the result to go back to these arrays and populate the data shown based on these.  Note especially that this happens every time a page in the paged view is selected.

This means that if you have a spry:if in your code, Spry runs over that for EVERY PAGE of the paged view, and does it EVERY TIME you navigate between pages.

Of course, this answers the question of what was happening to my code above.  Even though I was modifying the HTML elements of the "current library" to display based on selections, Spry didn't care what I had done once I changed the "page" of the paged view.  Rather, Spry re-evaluated the spry:if's, and re-rendered the element based on that.  Whatever parts of my changes that were in conflict with the spry:if were overwritten.

So obviously, simply modifying the HTML element itself is not enough to achieve the desired functionality. 

But never fear, for the solution is actually pretty simple. All we have to do in addition to modifying the HTML element is to also modify the array from which Spry is pulling its data each time.  As I mentioned, this is surprising simple to do.

For paged datasets, Spry stores the data items in an object called "unfilteredData".  So if my paged recordset is "pvRecords", the path in the DOM to the unfiltered data is simply "pvRecords.unfilteredData".  Now that I've accessed the array, I can search through the data items in it to find the one I want and modify it to the updated value.  Now, when

Spry evaluates the spry:if in the code, it uses the new value updated in the unfilteredData array, and renders correctly.

Here's an example of what I've done:

function modifySpryDataReference(title,dir) {

    var uds    = pvRecordsAlt.unfilteredData;
    for(i=0;i<uds.length;i++) {
        if(uds[i].TITLE == title) {
            uds[i].IN_PLAYLIST=dir;
        }
    }
}

In this example, I simply loop over the contents of the unfiltered dataset, looking for the item whose title matches the argument I pass to the function.  If a match is found, I access the "IN_PLAYLIST" item and change the boolean to whichever "direction" I'm going (e.g., whether I'm adding or removing a song from the playlist).  

So yeah, it's not too bad of a thing to do, and it helps to give a little better perspective/understanding on what Spry is doing under the covers :)

Dynamically Loading JavaScript...with Spry! 1 comments   |   Tags: Spry   JavaScript   Loading JavaScript   |   Sorta-Perma-Link

I've written a couple of articles in the last few months about my adventures in JavaScript.  While I certainly don't claim to be even proficient, I am getting better day by day.  As I pick up tricks and tips, I try to pass them on to help others out (hopefully!).  

Recently, we ran into an issue at work.  We're constantly adding JavaScript functionality to our company intranet.  While adding references to JavaScript files in the master pages that drive the templates is easy to do, there is a process that all master page changes have to go through, and this can limit the desirability of future changes.  What we needed was a way to dynamically load JavaScript files when needed, so that only the core init.js file that is loaded with every page request needs to be referenced on the master pages.

I've never done this kind of thing before, so I did a little snooping around.  There are apparently alot of solutions out there, some of them better and more robust than others.  After studying what they do, I decided to try my hand at building a simple JS loader in Spry, given that the core files I need are already in place.  Here's the result:

Spry.Utils.addLoadListener(function() { addEventHandlers() });

var wiki = 'wikicontent';

function addEventHandlers() {
    if (Spry.$$(wiki)) {
        loadJS('js/showlinks.js')
        getLinks();
    }
}
function loadJS(file) {
    var syncJS = Spry.Utils.loadURL("GET",file,false,addJS);   
}
function addJS(req){
    if (window.location.href.indexOf("http")==-1 || req.xhRequest.status==200) {
        var head = document.getElementsByTagName('head')[0];
        newJS = document.createElement('script');
        newJS.setAttribute('type', 'text/javascript');
        newJS.text = req.xhRequest.responseText;
        head.appendChild(newJS);   
    }
}

Turns out this is really easy.  The first thing you'll want to do, of course, is check to see if the element/function/etc that needs special JavaScript loaded exists.  In my example, I'm checking to see if the div that wraps a wiki element exists.

If it does, I call the loadJS() function (yes, I know, quite original!).  This function is really a go-between function that allows the meat of the process--the URL load--to be independant of this context and, therefore, reusable.  It takes only one argument: the relative path to the JavaScript file that needs to be loaded.

This argument is then passed to an instance of the Spry.loadURL function.  This function will make a synchronous XMLHttpRequest to the specified URL.  Easy.

Now for the most important part.  When the XMLHttpRequest returns a value, it needs to be written back to the DOM so that the functions included in the JavaScript file will be available for use.  This is accomplished on the callback function of the loadURL(), 'addJS'.  This function bascially takes the returned XML response, parses it, and writes it to a new script tag, which we create.  Finally, the new script tag is appended to the "head" tag of the page.

BIG GOTCHA:  IE7 will not recognize "innerHTML" for the script tag, so you have to use "text".  

That's it.  Now all functions and variable available in the requested JavaScript file are immediately available for use--in fact, this example makes a call to "getLinks()", the core function of the "showlinks.js" file.

Now obviously, this is an extremely simple example, and more complicated scenarios will require more processing, more capturing of errors, etc.  And one downside is that for this example, it require that SpryData.js, SpryDOMUtils.js, and an init.js be loaded with the page.  This could get a bit expensive, and less elegant (IMO) methods of accomplishing the same thing can occur with a tad less overhead.  Nonetheless, if you can spare the fractionally greater load times, it provides a simple way to make your coding even more flexible...and it uses Spry, to boot!

Flippin' Cool Spry Goodness 0 comments   |   Tags: Spry   JavaScript   Flippin' Cool   |   Sorta-Perma-Link
As followers of this blog know, I am a pretty big fan of Adobe's JavaScript framework, Spry. Admittedly, it's not a super-huge framework like jQuery, but I like its simplicity and how rapidly I can develop a solution with it.

One thing I've been frustrated with is Spry's effects. While they have some good effects, I never found them particularly flexible or usable beyond little dynamic enhacements. Apparently, most of this is because I hadn't read the documentation enough.

Enter effect clustering. Normally, Spry effects run in turn of function call: so if you have, say, a tool-tip that you want to fade out and move, these effects would run in order (which wouldn't really make sense to do anyway). However, as I discovered with great joy yesterday, Spry allows for something called "effect clustering" which allows any number of effects to be run in parallel with one another.

I about peed my pants when I found this out, it's so cool and useful. So here's an example of this in action.

And here's the code:

FadeMove = function(element, options) {
Spry.Effect.Cluster.call(this, options);

var duration = 1000;
var toggle = 'false';
var from = 100;
var to = 0;
var fromPos = new Spry.Effect.Utils.Position();
fromPos.x = 13;
fromPos.y = 0;
var toPos = new Spry.Effect.Utils.Position();
toPos.x = 13;
toPos.y = -65;
Spry.Effect.makePositioned(element);

var transition = Spry.fifthTransition;

if (options) {
if (options.duration != null) duration = options.duration;
if (options.from != null) from = options.from;
if (options.to != null) to = options.to;
if (options.transition != null) transition = options.transition;
}

var fadeOut = new Spry.Effect.Fade(element, {duration: 500, from: from, to: to, transition: transition, toggle: toggle});
var moveUp = new Spry.Effect.Move(element, fromPos, toPos,{duration: 800, transition: transition, toggle: toggle});

this.addParallelEffect(fadeOut);
this.addParallelEffect(moveUp);
};

FadeMove.prototype = new Spry.Effect.Cluster();
FadeMove.prototype.constructor = FadeMove;


Honestly, this is super-easy to do. You start by extending the Cluster class--any effects that you include in this extension now become a cluster.

FadeMove = function(element, options) {
Spry.Effect.Cluster.call(this, options);
.............
}
FadeMove.prototype = new Spry.Effect.Cluster();
FadeMove.prototype.constructor = FadeMove;


In this example, I want to have an effect that "fades" and "moves", so I called my class extension "FadeMove." You can call it whatever you want.

The next thing to do is to setup some default options for the effects you're going to be using:

var duration = 1000;
var toggle = 'false';
var from = 100;
var to = 0;
if (options) {
if (options.duration != null) duration = options.duration;
if (options.from != null) from = options.from;
if (options.to != null) to = options.to;
if (options.transition != null) transition = options.transition;
}


The function allows you to pass in your own options dynamically, so these are just here as a safety net.

Next, define your effects, just as you normally would for any Spry effect call:

var fadeOut = new Spry.Effect.Fade(element, {duration: 500, from: from, to: to, transition: transition, toggle: toggle});
var moveUp = new Spry.Effect.Move(element, fromPos, toPos,{duration: 800, transition: transition, toggle: toggle});


Simple. So now the only thing left to do is to tell the function that you'd like to have these effects run in parallel. As with all things Spry, this is cake:

this.addParallelEffect(fadeOut);
this.addParallelEffect(moveUp);


Guess what? That's it. There is nothing more to it than that. Seriously, I am completely psyched about abusing this new knowledge on all my projects. Be sure to check out my example.
AJAX Gotcha...POST vs. GET 3 comments   |   Tags: AJAX   Spry 1.6   CSS Gallery   |   Sorta-Perma-Link

A rather annoying issue I ran into this evening when testing my up-and-coming CSS gallery on a live server was that all of my cross-domain AJAX calls were failing in Firefox.  I'm used to stuff failing for stupid reasons in IE, but this one was unique.  I tested in Safari (for Windows), IE 7, and Opera--all of them worked beautifully.  But for whatever reason, Firefox horked on the code.

Well, it turns out it was a simple fix.  In my AJAX calls, I was using the Spry loadURL() function.  For this function, you can specify whether the call should be a "POST" or "GET" method.  I assumed for my remote calls that I would be doing POST methods.  

After all was said and done, it was apparently the POST methods that Firefox was having a coniption over.  I changed the methods really quickly to GETs, and everything worked again in all browsers.

As I am mostly stupid, I have no reason why this happened--however, perhaps this will be useful to some other poor code monkey out there who is betrayed by Firefox in the wee-hours of the night, and maybe a wiser soul would be kind enough to post a comment about the source of this error...please? :)

Coming Soon...Very Soon! 1 comments   |   Tags: CSS Gallery   Spry   AJAX   Web 2.0   ColdFusion   |   Sorta-Perma-Link

Remember the CSS Gallery I wrote about a while ago?  Yes, the one that I'm building?  Well, IT'S ALMOST DONE!!

I am incredibly excited.  The design, I feel, really came together, and the final result is something simple and sleek, but still (at least IMO) memorable.

One of the most exciting things about this project for me is that it's allowed me to flex some ColdFusion 8 muscles--muscles that I have had not yet really had a chance to use until now.

What kind of features are there going to be?  I'm glad you asked!

On the client side, I completely Web 2.0-ified the site submission process.  When you click "Submit", instead of getting redirected to a form page, I'm using Thickbox to present the form. The form itself is pretty sweet, too.  First, there's a fairly interesting hint tool that I developed.  But the power of the form is that not only does it check the XHTML and CSS validation on the site you enter while you're finishing up the form, but even the form submission itself is AJAXed.  No stupid submit and refresh here!

Once a site submission is approved and live, each site will have comments attached, as well as a rating mechanism.  As I blogged about a while ago, I'm going to use Spry's newest tool, the Rating widget.  It is awesome because not only does it manage all of the javascript stuff horribly simply, but it also includes built in methods for interacting with the server for saving and retrieving rating values on the fly.  

The thing I'm most excited about with this gallery, however, is that I've built it with lots of hooks into various webservices, AND I've made it so that I only have to click ONE BUTTON to create a new site.

First the hooks:  When I approve a new site, I tap into some simple webservice calls that hit Twitter to post an update, and ScrnShots.com to upload a new screenshot (the one I just approved).  But where did this screenshot come from?  Again, I'm glad you asked!

The power of my application is that I am lazy.  Let me explain.  For most CSS galleries out there, the process goes like this: someone comes to the site, submits a url, and waits.  The administration logs into their admin tool (most likely WordPress--boooo) and review.  If they approve it, they have to go to the site, take a screenshot, go into Photoshop and hack up 1, 2 or possibly three sizes for use on their site.  After this is done, they they have to upload and link the new entries into the site management piece. 

Okay, it works, but it's a lot of work.  I want a shiny button I can click, and be done with it.  SO...to accomplish this, I'm using a combination of a web snap-shot tool (WebSnapr.com) and ColdFusion 8's coolest new tag, cfimage.  

First, with WebSnapr.com, I have a http call hit their API and request a screenshot.  Their application goes out, takes a screenshot, and stores it on their server with a standard naming convention.  Upon my 1-click approval, I have cfimage run out to the web, grab the url and use its super-cool image magic to resize and crop the images into the sizes that I need and save them to my server.  Then an entry is made into my database with the correct thumbnail paths.  

But my laziness goes even deeper.  I've additionally built in a mechanism that allows me to approve site submissions from my email--still a click, but one less login. Huzzah!

So hopefully this now ridiculously lengthy post communicates how excited I am about this.  Stay tuned, for it will be coming soon and my readers will be the first to know! 

Spry's Rating Widget 12 comments   |   Tags: Spry Framework   AJAX   Delicious   |   Sorta-Perma-Link
For a new project I'm working on, I will need a mechanism for users to vote on certain pieces of content. Now it turns out that there are a billion and one ways of doing this, with an additional billion sets of frameworks. I was quite overwhelmed by the number of choices, so I've been putting it off for a while now.

Yet fortuitously, a couple days ago I was browsing the Spry docs and noticed two very promising words: Rating Widget.

Surely this cannot be what I'm looking for, could it? Ah but it was!

Recently, Spry updated its growing library of widgets to include a standard "star" rating system. Like it's other widgets, the rating widget comes with a single css file and a single javascript file. And also like other Spry widgets, it is completely simple to implement.

Assuming you have referenced the css and javascript files correctly, here's all it takes to set up a star rating system:

<span id="myrating" class="ratingContainer">

        <span class="ratingButton"></span>
        <span class="ratingButton"></span>
        <span class="ratingButton"></span>
        <span class="ratingButton"></span>
        <span class="ratingButton"></span>
        <input type="text" id="ratingValue" name="dynamic_rate"/>
        <span class="ratingRatedMsg">Thanks for voting !</span>
    </span>

It's so simple it's almost laughable. But it gets much better. Like all things Spry, this widget makes it incredibly easy to connect with other files that might handle server-side processing (such as computing the new average of votes based on user's selection). To do this, you just add an additional parameter to the widget that specifies the file that will be doing the processing, as well as any arguments that need to be sent along. Spry takes care of the rest. Oh, and there is also a handy parameter ('afterRating") that allows you to easily update the widget with the returned value from the original request, all completely asynchronously. And here's that:

var rate = new Spry.Widget.Rating("myrating", {ratingValue:2, afterRating:'serverValue', saveUrl: "rating.cfc?method=returnAverage",postData:"id=myrating&rating=@@ratingValue@@"});

Here, I simply instantiate a new widget, set a default rating "average" (2), specify the 'afterRating' to get the returned serverValue, and setup my url fetch with appropriate arguments. Absolute cake!

Check out an extremely stripped down version of all that the Spry rating widget is capable of doing.

Oh, and tomorrow I will follow up on this regarding how we move this already cool widget to full-on unobtrusiveness.

Adobe's Spry Framework, Part Second 1 comments   |   Tags: Spry Framework   Web 2.0   AJAX   |   Sorta-Perma-Link

A couple days ago, I posted an example of how Adobe's Spry Framework allows one to easily and quickly incorporate XML datasets into an application, allowing for a great alternative to page-to-page navigation and data mining.

One of the limitations I pointed out was the initial amount of coding involved. Well, that was because I'm an idiot.

While I've used Spry's Spry.Data.XMLDataSet() many times before, I literally had no idea how powerful it is, nor that it could interact with dynamically generated XML files, such as I was doing with ColdFusion components in my last example. However, such is not the case. Not only does this method allow me to do everything I was doing before, it involves a heck of lot less code. The entire invoke for the datasets here is:

 

var dsCities = new Spry.Data.XMLDataSet("getlocations.cfc method=getCities", "cities/city");

var dsLocations = new Spry.Data.XMLDataSet("getlocations.cfc?method=getLocations&cityID={dsCities::@id}", "locations/location");

 

Two lines of javascript! Now of course, there is more to handle some of the behaviors...but I have effectively cut out about 100 lines from what I was doing before. Pretty cool!

Finally, the best part about this is it allows me to take full advantage of the framework's "spry:state". With this, one can set different "states" that will fire in relation to the loading of the datasets. So, while the data is loading, one can display a sexy progress gif using "spry:state=loading". And when the dataset is retrieved, one can use "spry:state=ready" to display the returned datasets.

Oh yeah, one LAST thing. Using datasets like this makes dynamic callbacks a breeze. Imagine I have items that a user can save to their "favorites". Using the "spry:if", I can tell the browser to display certain elements certain ways depending on the recordsets that are returned (i.e., whether or not the user has a particular item saved to their favorites). Before Spry, I would have the user "save" the favorite which would reload the page, re-hit the database, and alter the display to show the changes to the data. With Spry, however, the page reload is no longer necessary. Rather, one can simply tell the callback function from the insert query to recompile the Spry dataset asychronously. Because the data that's currently being display is based on this dataset, the returned information will be refreshed automatically, all without the need of a single page reload.

Blah, blah, blah. Enough of this. Here's a slightly more sexy example of what I've been talking about.

Web 2.0 Goodness - Adobe's Spry Framework 1 comments   |   Tags: ColdFusion   Spry   Web 2.0   |   Sorta-Perma-Link
Ok, so as everyone who reads this blog knows (or should know...), I am a web designer/web developer. On the development side, I am best at ColdFusion , one of the under-appreciated programming langugages out there. While ColdFusion is awesome, one of the drawbacks of it (as well as of PHP, .NET, etc.) is that it is a server-side technology, meaning (surprise, surprise) that all of the code processing done is accomplished on the server. So, any of the cool Web 2.0 stuff out there, like asynchronous form submission, has to use Javascript.

While ColdFusion 8 has some seriously cool AJAX features built into it that handle alot of this kind of thing with ease, it is not free and wonderful hosting companies (like GoDaddy) are slow to upgrade their servers to the newest version. Therefore, the onus is upon the developer to utilize the various work-arounds until ColdFusion 8 is firmly entrenched.

One tool that makes life significantly easier is Adobe's Spry Framework . While Spry includes a lot of the cool effects of other Javascript frameworks, one of the best parts of it is the easy way in which it allows Spry to make server-side calls to allow applications to harness normally off-limits server-side functionality asychronously. For example, consider that I wish to display a list of businesses by city. I want to be able to display the businesses by city, as well as all without a filter on the city. To accomplish this without Javascript and ColdFusion alone, the standard practice would be to give each city link an ID that would be passed to the URL string. Then, when the page reloads, the variable passed to the URL string would tell the database to only show the records that are relevant to that variable.

While this works, it is not very sexy. It requires page reload after page reload just to see different information. Blah. Enter Spry. With Spry, the functionality works exactly the same. A variable is passed through a URL that tells the database to only return certain records. However, what is different is that Spry does not need page reloads. Rather, being the sexy little thing that it is, Spry is able to pass the variable to ColdFusion, get ColdFusion to process the variable on the server, return the variable to Spry, and then output it for the user to see---all without a single page reload.

While this is a great solution for the end user, it does require a bit more effort on the development side. With ColdFusion, I could normally do the database call, data processing, and data ouput in about 20 lines of code. Using Spry, however, has significantly increased that number, for besides having to outline--in Javascript--the various xhtml elements that I wish to populate with data, I also have convert my database queries to an XML format that Spry will be content to use.

Nonetheless, I think the number of lines of code is justifiable, and as I do this more, the coding time will be signficantly reduced. Plus, I think the end result is pretty dang cool.

Interested? You can see a very unsexy example here .