I am constantly surprised by the power and elegance of of JQuery and how using it can change they way you create web applications.

JQuery is not just a simple javascript library that makes ajax and javascript coding easier to write, it also allows you to separate your client-side logic from your html, making it much more cleaner and easier to maintain.

Lets see how JQuery can improve your html with a concrete example. The requirements are:

  • A html table that lists tickets
  • Table rows should be alternating (colored)
  • Table rows should have a mouseover highlight effect
  • If you click a row a ticket detail should be shown

First I will show how a non JQuery solution could look like, here is simple solution using a web forms repeater (chosen for good effect).

<asp:Repeater ID="ticketRepeater" runat="server">
  <HeaderTemplate>
    <table class="ticket-table" border="0">
      <tr>
        <th>Id</th>                        
        <th>Description</th>                        
      </tr>                
  </HeaderTemplate>
  
  <ItemTemplate>
    <tr class="even" onmouseover="highlight_over(this);" 
             onmouseout="highlight_out(this);"
             onclick="selectTicket(<%# Eval("Id") %>)">
      <td><%# Eval("Id") %></td>                    
      <td><%# Eval("Description") %></td>                    
    </tr>    
  </ItemTemplate>
  
  <AlternatingItemTemplate>
    <tr class="odd" onmouseover="highlight_over(this);" 
            onmouseout="highlight_out(this);"
            onclick="selectTicket(<%# Eval("Id") %>)">
      <td><%# Eval("Id") %></td>                    
      <td><%# Eval("Description") %></td>                    
    </tr>    
  </AlternatingItemTemplate>    
              
  <FooterTemplate>
    </table>
  </FooterTemplate>
</asp:Repeater>    

The worst part of the above code is the complete duplication of the entire item template, completely unnecessary in this case as the class name is only difference. I have seen the repeater being used like this in numerous examples and in real applications. The mouseover and mouseout part is something that could be handled by ":hover" css selector, however this is not supported by IE (without resorting to javascript methods).

Here is the above markup but now taking advantage of JQuery:

<asp:Repeater ID="ticketRepeater2" runat="server">
  <HeaderTemplate>
    <table class="ticket-table" border="0">
      <thead>
        <tr>
          <th>Id</th>                        
          <th>Description</th>                        
        </tr>
      </thead>
      <tbody>
  </HeaderTemplate>
  
  <ItemTemplate>
    <tr>
      <td><%# Eval("Id") %></td>                    
      <td><%# Eval("Description") %></td>                    
    </tr>    
  </ItemTemplate>                
              
  <FooterTemplate>                    
      </tbody>
    </table>
  </FooterTemplate>
</asp:Repeater>    

The alternating template is removed, so it the mouseover, mouseout and click event handler. How do we restore this missing functionality? Here is the JQuery javascript code that restores it:

<script type="text/javascript">
        
        $(document).ready(function() {
            
            $(".ticket-table tbody tr:not([th]):odd").addClass("odd");
            $(".ticket-table tbody tr:not([th]):even").addClass("even");
            
            $(".ticket-table tbody tr").mouseover( function() {                    
                    $(this).addClass("hover");
            }).mouseout( function() {
                    $(this).removeClass("hover");
            });
            
            $(".ticket-table tbody tr").click(function() {
                var id = $("td:first", this)[0].innerHTML;
                // handle the selection of this ticket id                                
            });
            
        });
        
 </script>

JQuery's strength is built around it's css based element selection expressions. The $() function is a JQuery function, which returns a list of elements that matched a JQuery "query". The list returned is a JQuery object which has a long list of useful functions (like addClass, hide, show, etc). The cool thing is that when you call a function like addClass, this action will be applied to all elements which the JQuery expression selected. Good bye to unnecessary loops! The mouseover/mouseout JQuery functions takes as an argument the handler for the event, and here you can just use a javascript closure. Fetching an id from the content of a table cell is perhaps not a recommended approach. It would be better to store it in the row element id.

The new solution introduced some extra lines of javascript code, but your html is much cleaner. The most important aspect is that you separate the behavior from the markup which will (hopefully) make the solution more maintainable.  The web forms repeater is a little verbose , it is surprising how much cleaner it can be if you just use inline scripting.  Here is how it would look like if you used MonoRails brail view engine:

<table class="ticket-table" border="0">
  <thead>
    <tr>
      <th>Id</th>                        
      <th>Description</th>                        
    </tr>
  </thead>
  <tbody>
  
  <?brail for ticket in tickets: ?>
      <tr>
        <td>${ticket.Id}</td>                    
        <td>${ticket.Description}</td>                    
      </tr>
  <?brail end ?>
  
  </tbody>
</table>

Another aspect where JQuery can be a big help is in web forms applications where element ids often complicate javascript code. I found that JQuery's element selection could in many cases work around this problem (by finding elements based on class name for example).

There is also a very large list of JQuery pluggins / extensions, here are two which I can recommend:

  • Validation (very feature rich client side form validation)
  • Metadata (allows you to have json metadata embedded in the html class attribute)

6 comments:

Andreas Öhlund said...

Interesting!

This looks alot like Phil Haacks repeater for ASP.Net MVC with the difference that this is done client-side

(http://haacked.com/archive/2008/05/03/code-based-repeater-for-asp.net-mvc.aspx)

Torkel Ödegaard said...

It was actually that post that prompted me to write this :)

Alexander Malfait said...
This comment has been removed by the author.
Alexander Malfait said...

A nicer way to do this is to just add the classes "striped" and "hoverable" to your table. In your javascript onload event, fetch all tables which have the striped/hoverable class and add your javascript behaviour.

This way you don't need to modify your scripts to apply the same behaviour to other tables in your app, as long as the script containing the onload event is loaded.

Torkel Ödegaard said...

@alexander: yes, that would be better!

Anonymous said...

Thank You