FLEX On jQuery: Turning HTML Links Into Standard UI Elements

Posted March 3, 2010 at 8:39 PM by Ben Nadel

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 »
11,243 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 »
9 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 »
11,243 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 »
9 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 »
11,243 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 »
11,243 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 »
22 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 »
11,243 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:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 23, 2013 at 5:19 AM
Ask Ben: Print Part Of A Web Page With jQuery
How to print also the background color of table cells and table lines ... read »
May 23, 2013 at 3:55 AM
Javascript Array Methods: Unshift(), Shift(), Push(), And Pop()
very interesting and helpful too. ... read »
May 22, 2013 at 5:35 PM
Script Tags, jQuery, And Html(), Text() And Contents()
This is still an issue 2 years later. jQuery is supposed to remediate these cross browser issues, no? I have been unable to find any statement from the jQuery team calling this behavior "by de ... read »
May 22, 2013 at 12:44 PM
Ask Ben: Query Loop Inside CFScript Tags
In cf10, if you call a function that has: local.result = {}; local.result.msg = ""; local.svc = new query(); local.svc.setSQL("SELECT * FROM..."); local.obj = local.svc.exe ... read »
May 22, 2013 at 12:29 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben: What version of Java are you using? Also, did you test users.id to see what Java reports as the data type? I wonder if it's not a Java primitive data type, but getting returned as something ... read »
May 22, 2013 at 11:47 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dana, Awesome - so it looks like this bug was fixed in ColdFusion 10. Thanks so much for double-checking that. ... read »
May 22, 2013 at 11:37 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
When I c&p and run on cf10, I get: Selected User IDs: 1,4 User 1 selected: YES - YES User 2 selected: NO - NO User 3 selected: NO - NO User 4 selected: YES - YES User 5 selected: NO - ... read »
May 22, 2013 at 11:27 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Tom, Good thought, but no dice. Both of these still exhibit the same behavior: users.id[ users.currentRow ] users[ "id" ][ users.currentRow ] It's just something whacky happening with ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools