Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at BFusion / BFLEX 2010 (Bloomington, Indiana) with: Ed Bartram

FLEX On jQuery: Turning HTML Links Into Standard UI Elements

By Ben Nadel on

In my first "FLEX on jQuery" blog post yesterday, I talked with Javier Julio about some of the similarities and differences between FLEX applications and rich jQuery applications. As we talked, one of the patterns that I began to see was the significant difference in the inherent power of "link" elements in the two different technologies. I say "link" in quotes because, as Dave Watts pointed out in my comments, there are no link elements in FLEX - there are simply UI elements that may or may not be used to trigger more meaningful, custom events. To create more of that kind of a context, I thought a good first exploration would be to create an application where HTML links are reduced to standard UI elements.

 
 
 
 
 
 
 
 
 
 

The reason that this is an important exploratory step is because the default behavior of links makes them, in a way, too powerful. The default behavior infers too much about how the click event should be handled. This assumption, while very useful in standard request-response work flows, becomes a deficit in thick-client, application-oriented model. By removing the default behavior of the link click event, we put our application at the top of our decision making tree; and while the difference might be purely emotional on some level, this makes our application feel more active and less passive.

The easiest way to accomplish this is simply to catch every click event at the document level and prevent the default behavior on the given event object. In doing so, we force our thick, jQuery application to actively respond to component-initiated events rather than the assumed intentions of events generated by the user interaction.

  • <!DOCTYPE HTML>
  • <html>
  • <head>
  • <title>FLEX On jQuery: Sample App One</title>
  • <script type="text/javascript" src="../jquery-1.4.2.js"></script>
  • <script type="text/javascript">
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  • // I am the list component class.
  • function ListComponent( list ){
  • var self = this;
  •  
  • // Get a reference to the list UI.
  • this.ui = list;
  •  
  • // Delegate all clicks within the "component".
  • this.ui.click(
  • function( event ){
  • // Get the target element.
  • var target = $( event.target );
  •  
  • // Check to see if a link was clicked.
  • if (target.is( "a" )){
  •  
  • // Blur the link - this is an example of
  • // the "component" responding to events
  • // internally without having to get the
  • // outside world involved.
  • target.blur();
  •  
  • // Trigger a custom click event this
  • // "component" to signal the click on the
  • // given link. Notice that we are passing
  • // additional event data as defined by
  • // the COMPONENT - not by the markup.
  • self.ui.trigger(
  • "viewGirl",
  • [{
  • name: target.text(),
  • type: target.attr( "rel" ),
  • href: target.attr( "href" )
  • }]
  • );
  •  
  • }
  • }
  • );
  • }
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // When the DOM is ready, initialize the scripts.
  • jQuery(function( $ ){
  •  
  • // Bind the click handler to the document so that we
  • // can catch every single click that bubbles up the
  • // DOM tree.
  • $( document ).click(
  • function( event ){
  •  
  • // Check to see if this click was triggered by
  • // an HTML link element.
  • if ($( event.target ).closest( "a" ).size()){
  •  
  • // Prevent the default event action. By
  • // default, the link click has TOO much
  • // power in a thick client app. Allow
  • // propagation, but prevent any navigation.
  • // In this way, we will only be responding
  • // to events triggered explicitly by
  • // components.
  • event.preventDefault();
  •  
  • }
  •  
  • }
  • );
  •  
  •  
  • // Create the component class instance for the given
  • // list element.
  • new ListComponent( $( "ul" ) );
  •  
  • // Bind to the UL component interface.
  • // NOTE: I think we should *probably* be binding to
  • // the actual component itself (defined above). But
  • // since jQuery provides such nice EVENT BINDING out
  • // of the box, we'll take this short-cut just for
  • // the exploration of this concept.
  • $( "ul" ).bind(
  • "viewGirl",
  • function( event, girl ){
  •  
  • // Log event to the console.
  • console.log(
  • ("Name: " + girl.name),
  • ".. // ..",
  • ("Href: " + girl.href),
  • ".. // ..",
  • ("Type: " + girl.type)
  • );
  •  
  • // Update the hash value of the window's
  • // current location. Notice that we are using
  • // an attribute *other* than the HREF to set
  • // the hash - the hash is no longer related
  • // to a link URL.
  • location.hash = girl.type;
  •  
  • }
  • );
  •  
  • });
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <h1>
  • FLEX On jQuery: Sample App One
  • </h1>
  •  
  • <!--
  • We are going to consider this List our "component" that
  • will have its own set of events and behaviors.
  • -->
  • <ul>
  • <li>
  • <a href="lisa.htm" rel="Hot">Lisa</a>
  • </li>
  • <li>
  • <a href="joanna.htm" rel="Hotter">Joanna</a>
  • </li>
  • <li>
  • <a href="tricia.htm" rel="Hottest">Tricia</a>
  • </li>
  • </ul>
  •  
  • </body>
  • </html>

As you can see, our call to event.preventDefault() in the document-click handler removes all default link behavior. In order for our application to interact with the ListComponent then, it must explicitly bind to the "viewGirl" event that the ListComponent is known to announce (trigger). And, in order for the ListComponent to generate the custom event, "viewGirl," it must listen for click events that occur locally to itself; in this way, the ListComponent can take some of those local events and use them to generate custom events.

When we approach our application architecture in this way, we leave the processing decisions up to the application's business logic and not to the HTML markup. Now that's not to say that we can't still get some of the inherent benefits of links; in this example, you'll notice that I am still changing the URL hash (theoretically used for later deep-linking). The difference here being that the hash was changed actively by the application itself, rather than passively allowed by proxy of the link.

While this might seem excessive for such a small example, I have a gut feeling that this kind of intent-driven mentality will go a long way with very complex, jQuery applications. Of course, please keep in mind that this is my first time doing this kind of cross-technology thought experiment. If you have something you'd like to add, please let me know in the comments. If you'd like to be part of the FLEX on jQuery discovery conversations, just drop me a line - I need all the help I can get.




Reader Comments

I think this is a really smart idea, looking at Flex to better understand jQuery...I don't know if it is true, but I have heard (read) a few different folks mention that jQuery is based or inspired by Flex/ActionScript 3.0.

And it does seem as if javaScript is doing things now, that just a short time ago could only have been done in ActionScript/Flex. Looking forward to reading the rest of the series.

Yeah, but where are the pictures of Lisa, Joanna and Tricia? How do we know that they are hotties? Just trust you? C'mon Ben, post the pictures.

Nice demo anyway. Thanks

@Mark,

I think a lot of the event management stuff in AS3 is based on the DOM event standards (though not sticking to those standards); so, it wouldn't surprise me if there was a lot of overlap.

@Anon,

Ha ha, I'll try harder next time :)

Excellent Demo! I see and understand how this works, but I guess I'm still struggling to wrap my head around when to use this jQuery approach (or Flex) as a full blown application over a traditional web app approach? ... Maybe this isn't the right place for the question, but would like to get your thoughts (or anyone elses) on this.

@Peter,

That's an excellent question, and one that I am sort of trying to think more deeply about. In my work, I tend to build more inner-facing web sites (company extranets / intranets); as such, the usability and efficiency of the application tends to be more important than what we might typically consider "entertainment" value. As such, I am trying to figure out how to make my client layer a bit thicker to make them snappier and more responsive to the user (ala GMail and things of that nature).

Of course, at what point do you have a VERY beefy single-page app... and at what point to have less thick, individual pages (more the traditional style)?

I don't know yet. At some point, it's probably a leap of faith. Meaning, right now, I cannot even imagine building an app in a FLEX-style, load-at-the-onset strategy. But, perhaps that is just a reflection of my disbelief that it can be done. After all, it works for FLEX.

I hope to be able to answer that question more thoroughly soon :)

@Ben,

Thanks for the reply. At the health care organization I work for, I build more traditional apps in an MVC format, with certain parts containing jQuery / ajax (where it's useful, auto-lookups, partial data views, binding select boxes, etc). I too am in the same boat where usability and efficiency is the most important thing, the end-user really doesn't care about the "entertainment" factor. So I guess the million dollar questions is When is it overkill to use Flex? I'll look out for your thorough answer soon!! Keep up the great work you do here!

@Peter,

Yeah, that's how I build to - we have AJAX and jQuery where is enhances a given page... but we don't require it to tie the entire application together (it's still very much a request-response life cycle).

As for overkill? I'd wager a bet that the FLEX people would say it's never overkill? I'd have to imagine that would defeat the entire purpose of the Flash Platform.

I recently came across your blog and have been reading along. I thought I would leave my first comment. I don't know what to say except that I have enjoyed reading. Nice blog. I will keep visiting this blog very often.

@Alex,

Thanks a lot - I'm glad you dropped in a comment. What kind of development do you do? Is there anything in particular you'd like to see discussed here?

@Johan,

Wow, that's pretty awesome! I very very briefly looked into SproutCore months ago, but never really got into it. Data binding is a powerful feature. Thanks for passing that along.