Ext JS 4.1 Grid: Part1: Basic Config

Many moons ago, I wrote a series on My First Ext JS Data Grid. It was very popular. In fact, it got me the gig co-authoring two books on Ext JS and spawned an open source project targeted at integrating Ext JS with ColdFusion. But, I did that series back in 2007, using Ext JS 1.1 (maybe?), and an update is long overdue.

[More]

CFQueryReader 2.0: Site and Demo Updates

Note: I mistakenly posted this under the wrong title. I must get more sleep ;)

I finally got around to a major overhaul of the CFQueryReader site, including all new demos and documentation of the latest build for Ext JS 4.x.

The new demos for Ext JS 2.x and 3.x include links to legacy API's for both versions of the library. The 3.x version includes an example of using Ext Direct, and the new 4.x demo includes paging data grids.

(Big thanks to Loiane's Ext JS 4 First Look, which showed me very quickly how dead simple Ext JS grids and data stores have become.)

I have not yet tested CFQueryReader with Sencha Touch, but it should work. Any feedback just let me know.

Ext JS 4 and ColdFusion: CFQueryReader 2.0

Wow! It's been too long. I've been so buried playing with new stuff I haven't had much time to write about it. Time to rectify that.

My position over the last year and a half hasn't required me to use Ext JS. And without a project I really haven't had much time to dive in to Ext JS 4. But, I am reviewing Loiane's Ext JS 4 First Look right now, and decided the simplest way to get in was to apply what she was telling me. I knew some of the basics, but Ext JS 4 is a big change, and Loaine's book quickly helped me to grok differences in the class model, updates to the data api, and more. In no time at all I had completely rewritten CFQueryReader, for parsing the native JSON return of a ColdFusion query object. I need to verify, but I'm fairly certain there are more lines of comments than there are code, in the new file. And it is wicked simple. First, include the js file, then define a record of data:

[More]

Intro to jqGrid Part 7: Grouping

OK, I know I said I was done, but I kept playing around and figured I should share. jqGrid, like other (read: Ext JS) good grid implementations, has the ability to group your data. What does that mean exactly? Well, let's look at our demo for inspiration. We've created a grid of blog post entries. Entries have associated Categories. We can reconfigure our grid to show the entries grouped by Category, with Category headers and accordion like separation.

[More]

Intro to jqGrid Part 6: The Action Column

So far we've covered the base grid configuration, populating the grid with remote data, controlling layout by refining the column model, and given an example of event handling by binding a search form to our grid. This covers most of what the average developer might need to know about working with jqGrid, but I've been promising to tell you how to work with the icons we setup in our action column.

[More]

ColdFusion JSON Serialization Changes

Because I've had to search on this three times in the last year, I thought it'd be a good idea to document this here, for myself and others. There were a number of important changes that can trip you up from version to version and, if you know which version the changes came in it can be beneficial.

First is a change that affects JSON output, though it's not specifically about JSON. The ColdFusion 9.01 updater (the current base install, at the time of this post) addressed Bug 82980 by removing ColdFusion Debug Output from direct CFC requests. This was only important if you had debugging output turned on in the Administrator, but caused lots of issues when testing ajax applications in development environments that kept that setting on by default.

Unfortunately, Adobe made some changes to JSON serialization that were not only unpopular, but technically dead wrong. They were trying to resolve the treatment of numbers in JSON serialization. Numbers were being converted to floats (1 became 1.0, 12 became 12.0, and so forth), so Adobe changed that by converting all numbers into strings (11 became "11", 17.24 became "17.24"). This was wrong too, as numbers weren't numeric anymore. At the time it raised quite a stir.

They fixed this (Bug 83638) really quickly, releasingCumulative Hotfix 1 for ColdFusion 9.01, which fixed the issue of integers being converted to float and having them as numeric values (ie: [1,12,true,"this var",17.24]). Hurray! Except....

Enter the improperly titled Cumulative Hotfix 2 for ColdFusion 9.01. I say this because it really isn't 'cumulative'. Most things are straight, from a cumulative standpoint, with the seeming exception of the fix to JSON formatting. If you have not applied CHF 1 prior to installing CHF 2, then you will still have issues with JSON formatting.

Overall, Hotfix 2 is great, fixing many bugs. The install is crazy/scary, and must be followed to the letter to prevent major issues, but it's worth it. As long as you did apply CHF 1 first, that is. Thankfully the hotfix/upgrade install process is much better in ColdFusion 10.

Big thanks to Ray for helping me to realize that I wasn't crazy, and pointing me in the right directions for all of this info. Hopefully this helps someone down the line.

MSOC Part 9: Application Event Handlers, The Rest

So far we've spent a lot of time going over the different Application Event Handlers that relate to specific scope events (application, session, and request). Some ask "How does this relate to MSOC?", to which I have to say "Because it's important to understand application flow and control." We'll be diving into the MSOC specific bits much more in the coming posts. For now, let's wrap this part of our MSOC talk with a brief discussion of our two final Application Event Handlers: onMissingTemplate and onError.

The onMissingTemplate handler kind of does what it says. ALERT: Pay Attention To This Next Statement. This handler will be automatically invoked when a ColdFusion template or component is called but does not exist. Did you catch that? Yes, this only catches requests for templates/files that might be served by the ColdFusion application server. Setup a special mapping for CF to process .inc files? Yes, if the file doesn't exist, then this handler should catch that. A .html page was requested? Unless the server is mapped for CF to handle those requests, then no, your onMissingTemplate method will not catch that error. You get the picture yet?

The basic layout of the onMissingTemplate method is like this:

view plain print about
1/**
2 * FUNCTION onMissingTemplate
3 * Runs when a (CF) template is called that does not exist
4 * @access public
5 * @returnType boolean
6 * @output false
7 */

8function onMissingTemplate(required string targetpage) {
9    // something goes here
10    return true;
11}

As you can see, this method is automatically passed one argument, the page being requested. Here's another catch for you, this will only catch requests for ColdFusion processed files in the same directory as your Application.cfc. So a request for mysite.com/nothere.cfm will be caught, but a request for mysite.com/some/random/path/to/nothere.cfm will not (This surprised me too, and I had to test it over and over again to make sure I wasn't missing something). Weird, huh? Well, that's ok. To be honest, the onMissingTemplate handler is better served by those who don't have access to change their own webserver. The better option is to setup a 404 handler in their web server configuration. In the Apache Web Server you can look for the ErrorDocument line, in your httpd.conf file, and set it to a specific template that you setup for error handling.

view plain print about
1ErrorDocument 404 /errors/404.cfm

Speaking of error handling... You do do error handling, right? You wouldn't just show end users hard errors, would you? Of course not. You've got try/catch, throw and rethrow all over the place, right?

I've never seen an app that was made to handle every possible scenario for what a user could do. Nope, never. And, I've never seen (or written) a perfect app. It's a mythical creature, like the unicorn, or honest politicians.Fortunately, Coldfusion gives us multiple levels of error handling capability, from the block level of try/catch to the server level error handler applied through the CF Administrator. The onError method allows us to apply an application level error handler, that catches anything not previously coded for (through try/catch). It can display (if desired) any error thrown from onApplicationStart through onRequestEnd, including errors thrown through the process of the request itself, but can not display content for errors thrown in the onSessionEnd or onApplicationEnd.

The onError event handler is formed like this:

view plain print about
1/**
2 * FUNCTION onError
3 * This is an application wide error handler. Best practice would be to
4 * write process specific error handling, but this method will help
5 * you trap unexpected errors for custom notification and process
6 * @access public
7 * @returnType void
8 * @output true
9 */

10function onError(required exception, required string eventname) {
11    if(StructKeyExists(APPLICATION.cfc, "errorHandler")){
12        // If the error is thrown in onApplicationEnd or onSessionEnd, the error processor
13        // will still run, but nothing will be displayed to the user
14        WriteOutput(APPLICATION.cfc.errorHandler.process(argumentCollection: ARGUMENTS));
15    } else {
16        WriteDump(var = ARGUMENTS.exception, abort = true);
17    }
18}

The onError method is automatically passed to argments, exception (think CFCATCH) and eventname (the application event that the error was thrown in). In my example, I've used an application wide error handler to process the error, and displayed it's output (if not thrown from onSessionEnd or onApplicationEnd). My handler could do any number of things, from logging to emailing the site admin to generating error code specific text response for output, to all of the above and more.

OK, that's it for the Application Event Handlers. Let's be honest, I really only glossed over them and they still took up a lot of posts. That said, it's time to get back to the core MSOC talk, even as important as understanding all of this might have been. We have things to talk about, like directory structures, shared and specific asset handling, extended application models, and more. Give me your feedback: What are your most pressing questions on running Many Sites with One Codebase?

The Joys of Developing for Internet Explorer

Note: Follow the madness here to it's conclusion, to discover yet another "Really? I didn't know that..." IE moment, that may save you heartache and pain.

Is the sarcasm evident in my title? It should be. While Internet Explorer may have been "groundbreaking" when it was released, it has ever been the bain of the web developer's existance. Why, you ask? Because it refuses to adhere to standards, and just operates differently than everyone else. To be fair, Internet Explorer 10 is in the works, and supposedly closes the gap a fair amount (and even wins out in some of the html 5/css 3 support), and 7, 8 and 9 did progressively improve (if slowly). Unfortunately the fact remains that some companies/organizations/governments are stuck on Internet Explorer 6, or maybe even 7. If you are a web developer, and write cross-browser web applications, chances are Internet Explorer has hit you more than once in your career.

It's the dumbest things that hit you too. The most obscure "WTF!?!" moments that drive you crazy. That is a daily experience for me now.

[More]

Intro to jqGrid Part 5: Search

At this point we've created a basic grid, filled it with data, refined the display of our columns and added event handlers to handle multiselect options. We've used custom cell formatters, used a custom datatype function, and even added and populated a toolbar in the process. Now let's start looking at some things that aren't necessarily jqGrid specific, but incorporate them for use in our grid. How about a search?

jqGrid includes some things for doing data search, that will automatically build modal windows and stuff. But sometimes you want to format things your own way, or incorporate jqGrid for use within an existing interface. One of the advantages for us, using the datatype function, is that we can preprocess our postdata prior to the ajax request.

[More]

Anatomy of a Shopping Cart: A Usability Study

This little writeup is a usability study of cart layout and process in general. So many apps today are still sporting the 1999 click-and-reload interface, and times have changed. Users are tired of the old way, embracing the new, and if you're behind the times you could be losing clients fast.

Shopping Carts are funny, terrible things. The less intuitive they are, the higher the abandon rate, and yet you have to pack a ton of stuff in there. The trick is to anticipate user workflow, and match that as much as possible, without making the user work for it too much. This is the whole precept behind Don't Make Me Think.

First things first, create a method for detecting JavaScript prior to a user ever coming to the shopping cart, as it redefines the experience for the user entirely. If JavaScript isn't present, then it's either a bot, some non-Class A mobile device, or less than 1% of the desktop user. Surfing the web without JavaScript is even less of a chance than a user surfing without the Flash player. There's just too much of a user experience that is lost without it, and most standard users don't have a clue how to disable it to begin with.

You end up with two separate cart processes, one with JavaScript, and one without. "Two processes?" Well, you write a process with graceful degradation, that can do what needs to be done in either scenario, and with code reusability in mind. This writeup will go over the user with JavaScript enabled.

I've mocked up a simple, yet effective, cart design. This is just a wireframe model, but there's nothing here that can't be done with HTML and CSS. A user without JavaScript would have to step through the stages of placing an order, screen by screen. A user with JavaScript has to step through as well, but through JavaScript and Ajax, this user does most of their work right from the cart.

Below is the mockup, with an explanation of the different stages of process to follow:

This is pretty loose. Balsamiq only allows you to do so much, so color and highlights and icons give things a lot more pizazz, but this should give you a good idea. If you're unfamiliar with Balsamiq, it's a great tool for doing simple "pen on napkin" wireframe layouts during interface design. It's also a great way to draft quick mockups for clients without spending hours of unpaid time, and even more hours on revisions.

From the top down:

The only button at the top is the "Keep Shopping" button. A user has to verify all the details prior to checking out, so the "Checkout" button is at the bottom of the form. The "Clear" button is also at the bottom, giving the user a second chance not to clear out. A second "Keep Shopping" button is at the bottom of the page, to encourage the user to buy more.

Next up is the cart contents. A user, coming to the cart, wants to know what's in it first. This is the user's main focus, so registering for the site or entering credit details and stuff always comes after the cart itself.

There are a few different ways to handle actions on cart items. Here I show the 'Remove' checkbox. If a user hits the box, take the item out. Don't prompt 'Are you sure?' This annoys users. Of course they're sure, or they wouldn't have checked the box. Another way of handling 'Remove' is part of an action link list. There are already two other action links showing (Gift Wrap and Add to Registry), it would be easy to adjust the layout to use all action links instead (Remove at the top, Add to Wishlist, Add to Registry, with Gift Wrap last). Here's a tip though: Any of these actions will ultimately remove the item from the cart.

Being tabular in nature, it's best to use a table here. Unwritten rules of cart usability: the 'Item' is listed first, unless something small, like a checkbox, radio button, or icon precedes it. The cost (Qty * Price) is always last. This allows us to build a columnar layout of the money details. If you have line item discounts, you may show the math here too, to emphasize what the client is getting. In this mockup, it's all shown below.

Next, show the user some love. Discounts, Promos, Gift Cards and Coupons should follow the cart. 1) it makes it easier to calculate the Subtotal and 2) it gives the user a warm fuzzy to watch their Total decrease. If there were discounts on items, pull them out here (if you didn't do it above). Don't make a user refresh the page to get a new Total. Gift Cards and Coupons? Use Ajax to verify their validity and value, and apply it to the tally block right then.

If addresses aren't pre-populated, then the user hasn't logged in or registered or set up addresses yet. Our action depends on which scenario is the case. If the user hasn't logged in or registered, then we show them a login box, with a register button. If they login, we go ahead with the rest of the order process. If they must register, handle that registration in a modal popup and then update your area. If the system allows for anonymous users (those who don't want, or have, to register with the site), or a registered user hasn't setup addresses yet, then we display "add address" links to the display that can load modal forms to collect the necessary details.

You can't tally Tax unless you know you need to collect it. If you don't have an address yet, don't show the Tax line item. If you get an address, and tax does need to be applied, add it in right away, and highlight it, and the Total change, so there's no surprises.

And, once you have an address, then you already know the zip/postal code the order is going to. Once a Shipping Method is selected we can lookup the shipping cost via Ajax. And, if the purchase is a download, then there's no reason to show them the Shipping line item at all. Avoid the "Estimated Shipping" thing, just give them the info once you have it. If need be, show them text ("We need your address and Shipping Method to show Shipping Cost") to help push them through the order process.

Last is the Payment Method. When a user selects the Payment Method, then the input fields for this area should change to the appropriate fields for that method. Don't show them fields for every possible option, just those for the option they've chosen.

That's it. By streamlining your Cart and Checkout process to match user workflow, you should see a lower abandon rate and higher sales. There's a lot of code involved, and both client-side and server-side data validation is a must, for security purposes, but the end gain makes the effort more than worthwhile. What are your suggestions for improving Cart usability? Give me your feedback below.

Previous Entries / More Entries