FLEX On jQuery: Turning HTML Links Into Standard UI Elements

Posted March 3, 2010 at 8:39 PM

Tags: Javascript / DHTML

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

Mar 3, 2010 at 11:22 PM // reply »
1 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.


Mar 4, 2010 at 12:06 PM // reply »
1 Comments

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


Mar 4, 2010 at 12:49 PM // reply »
8,824 Comments

@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 :)


Mar 9, 2010 at 1:33 PM // reply »
8 Comments

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.


Mar 10, 2010 at 9:55 PM // reply »
8,824 Comments

@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 :)


Mar 10, 2010 at 11:00 PM // reply »
8 Comments

@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!


Mar 11, 2010 at 7:57 AM // reply »
8,824 Comments

@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.


Mar 31, 2010 at 2:36 PM // reply »
1 Comments

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.


Mar 31, 2010 at 2:38 PM // reply »
8,824 Comments

@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?


Apr 18, 2010 at 6:34 PM // reply »
14 Comments

Hey Ben - I recall reading something about jQuery and Flex style data binding somewhere on your blog but could not find it.

I came across this demo from SproutCore that I though may give you some ideas:

http://demo.sproutcore.com/bindings_overload/

http://wiki.sproutcore.com/Runtime-Bindings


Apr 19, 2010 at 9:51 PM // reply »
8,824 Comments

@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.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Formatting: <strong>bold</strong> <em>italic<em>







  • Help Wanted - Find Your Next ColdFusion Job
Recent Blog Comments
Sep 5, 2010 at 6:35 PM
Muscle: Confessions Of An Unlikely Bodybuilder By Samuel Wilson Fussell
@Ben, Certainly will/ Thanks Sean ... read »
Sep 5, 2010 at 6:26 PM
Experimenting With HTML5's Cache Manifest For Offline Web Applications
@Ben, Yes, I am using Firefox Portable. At the moment I run a portable web server on the stick which holds and serves all files. The good thing is, I can run PHP pages on the stick to do requests to ... read »
Sep 5, 2010 at 5:05 PM
Ask Ben: Finding XML Nodes That Have Children With The Given Case-Insensitive Phrase
@Murray, Good point on the clarification. ... read »
Sep 5, 2010 at 4:40 PM
Ask Ben: Finding XML Nodes That Have Children With The Given Case-Insensitive Phrase
Actually, for the benefit of anyone reading this who might want to make sense of the question post, the first <td> had a bold tag surrounding the numeral 6. So, the problem was that the xmlSear ... read »
Sep 5, 2010 at 4:35 PM
Ask Ben: Finding XML Nodes That Have Children With The Given Case-Insensitive Phrase
Thanks Ben. Much appreciated. ... read »
Sep 5, 2010 at 3:39 PM
jQuery forEach() Experiment For Branch-Wise Implicit Iteration
@Sereal, Wow - what a super flattering thing to say :) I really appreciate that! I'm so happy that this stuff is providing value for you. ... read »
Sep 5, 2010 at 3:32 PM
Escaping Form Values - Understanding The ColdFusion htmlEditFormat() Life Cycle
@Ben, There's also a performance benefit to escaping on database insert since it only needs to be done ONCE - when inserting. When you escape on output, this needs to be done every time you output ... read »
Sep 5, 2010 at 3:30 PM
XML Building / Parsing / Traversing Speed In ColdFusion
@Don, I've played around with a couple of approaches to dealing with XML documents that are too large to be parsed in one shot. In one, approach, I use Regular Expression to try and parse one tag a ... read »