Halhelms
SIGN UP FOR MY NEWSLETTER

www.savorgold.com is top on wow gold and runescape gold and World of Warcraft gold provider list for trusted services. Their reputation seems to growing by the minute, which isn't surprising because they are one of the safest sellers of Gold. Delivery speed and customer service are very good. They aslo are giving some bonus items depending on the amount of gold you purchase.

 
 
Halhelms

Recent Comments

Recent Entries

RSS

jQuery Custom Events : A Deeper Look

In the last post, we got started with event driven programming. In this post, we're going to look a bit more at the mechanism for event driven programming, jQuery's custom events.

DOM (Document Object Model) events are those spawned by the browser. They're triggered by things like clicking buttons, hovering over an element -- even moving your mouse. Most of these events are ignored, but they exist because someone, at some time, might need to know about them. Custom events are those that you generate and they indicate that the state of the application has changed.

What sort of custom events would an application have? Here are a few an architect might decide on for an ecommerce application:

  • The user adds a product to her cart
  • The system determines some of the items in the cart are not in stock
  • The user wishes to rate a product
  • The user wishes to speak with a customer service representative
  • The system determines the credit card entered is invalid

In short, anything the system or the users of the system need to react to is modeled as a custom event. In "Getting Started With Event Driven Programming", I showed you some code for announcing (also referred to as "generating", "publishing", "notifying", "triggering", etc.) an event. The base pattern is this:

$( element ).trigger(
  eventName
  [, eventObject]
);

We see that triggering a custom event requires an event name; this is the key that allows others to listen for events. At times, no other information is needed: the name suffices. Most of the time, though, listeners require more information to react to that event. In the example of a user adding a product to their cart, listeners would probably need to know some or all of the following:

  • user_id
  • product_id
  • quantity_added

I've put together a -- well, let's be charitable and call it "rudimentary" -- shopping page, which you can see here:

2010-10-24_03333

In fact, this could be a prototype. Working with a prototype allows us to concentrate on the system rather than the code -- and most successful architects want to think about the system in its entirety before dropping to the code level. (This approach to system architecture is known as Interface Driven Architecture (IDA). If you're interested in Interface Driven Architecture, here's a booklet I wrote for budding software systems architects: Obsessively Through Software Design..) In the next blog post, I'll talk about my method for using the prototype to identify events, but this one is so simple that we'll use only one event: item_added_to_cart.

This is the code behind that page:


  <head>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
  </head>
  
  <body>
    <div id="products">
      <h4>Products</h4>
      <p>Here's a list of books we thought you might find interesting:</p>
      <div>
        <h3>Adobe ColdFusion Anthology</h3>
        <img src="images/cf_anthology.jpg" alt="Adobe ColdFusion Anthology" width="75" height="75" /> 
        <label>Qty: </label>
        <input type="text" size="2" id="1430272155" />
        <img src="images/add_cart.jpeg" 
          alt="add_cart" 
          width="47" 
          height="42" 
          data-name="Adobe ColdFusion Anthology" 
          data-isbn="1430272155" 
          class="add_product" />
      </div>

<div> <h3>High Performance JavaScript</h3> <img src="images/javascript.jpg" alt="High Performance JavaScript" width="75" height="75" /> <label>Qty: </label> <input type="text" size="2" id="059680279X" /> <img src="images/add_cart.jpeg" alt="add_cart" width="47" height="42" data-name="High Performance JavaScript" data-isbn="059680279X" class="add_product" /> </div>

<div> <h3>Event Processing in Action</h3> <img src="images/edp.jpg" alt="Event Processing in Action" width="75" height="75" /> <label>Qty: </label> <input type="text" size="2" class="add_product" id="1935182218" /> <img src="images/add_cart.jpeg" alt="add_cart" width="47" height="42" data-name="Event Processing in Action" data-isbn="1935182218" class="add_product" /> </div>

</div> <div id="cart"> <h4>Your Cart</h4> <ul id="cart_items"></ul> </div> <script type="text/javascript"> // when an item is added to the cart... $( '.add_product' ).click( function(){ var isbn = $( this ).data( 'isbn' ); var title = $( this ).data( 'name' ); var quantity = $( '#' + isbn ).val() ? $( '#' + isbn ).val() : 1; var eventObject = { isbn : isbn, quantity : quantity, title : title }; // ... announce it $( '#products' ).trigger( 'item_added_to_cart', eventObject ); }); </script> <!-- Listeners --> <script type="text/javascript" src="CartListener.js"></script> </body> </html>

I'd like to draw your attention to the bottom of the page. Notice that, while we're announcing ("trigger" injQuery vocabulary) the event, item_added_to_cart, there's no one listening ("bind" in jQuery vocabulary) for it -- at least not on this page. You can see, though, that there is a script tag that includes the file CartListener.js. Do we put the code for listeners in separate files just to keep things tidy? Well, that's a good reason, but there's more at play here.It goes back to the idea of keeping each piece of a complex application as simple as possible. This principle is known as separation of concerns. It might not going too far to call it mind your own business.

The shopping page is there to present items to a potential customer. The steps that should happen if that potential customer decides to buy is beyond the purview of that page. Other listeners -- in other files -- might also be listening. The keys to event driven programming are:

  • Publishers of events are unaware of who may be listening
  • Listeners of events are unaware of who may be publishing
  • Listeners of events are unaware of who else may be listening

In this way, we have excellent separation of concerns.

In this example, there is someone listening for a user adding an item to the cart: the CartListener.

Here is the code for CartListener.js:

// Cart Listener  
$( 'body' ).bind(
  'item_added_to_cart',
  function( event, eventObject ){ 
    $( '<li>' + eventObject.quantity + 
    ' ea. ' + eventObject.title + 
    '</li>').appendTo( $( '#cart_items' ) );
  }
);

With jQuery, we bind to events when we want to listen for them. The pattern is this:

$( element ).bind(
  event_name,
  function( event, eventObject ){
    // code to respond to the event
  }
);

In the Model-View-Controller pattern, it is the Controller that is responsible for connecting the right listeners to the right pages. While this is a highly-simplified example, in a real world one, the Controller might include multiple listeners. Some of these listeners will overlap the events they listen for, but each listener will only listen for events that pertain to it and each of these listeners will take the appropriate steps it needs to in order to react to the event.

In the next installment, I'll talk about identifying events using the Interface Driven Architecture I spoke of earlier and in a future post, we'll examine which elements we choose to attach trigger or bind to.

For now, our code in action:

The sample code is available at http://github.com/halhelms/Blog-Post--jQuery-Custom-Events---A-Deeper-Look

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
 
   
Clicky Web Analytics