When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article

ASP ASP.NET ASP FAQs Message Board Feedback
 
Print this Page!
Published: Wednesday, February 16, 2005

An Easier Way to Highlight the Rows of a DataGrid on MouseOver

By Steve Stchur


Introduction


By now, virtually every ASP.NET developer is familiar with the DataGrid control, an extremely powerful and versatile control for displaying data. (If you are not familiar with the DataGrid, I suggest that you start with Scott Mitchell's An Extensive Examination of the DataGrid Control article series.) Personally, I've used the DataGrid control in numerous projects and often find myself trying to make the DataGrid's rendered output more aesthetically appealing. One such aesthetic technique, used by sites like Yahoo! Mail and Hotmail, is automatic highlighting of the row the user's mouse is positioned over. That is, when the end user moves his mouse over the DataGrid's data, the DataGrid row the mouse currently resides over would have a different background color than the other rows.

You may actually know how to accomplish mouse-based row highlighting already, as there have been numerous articles written about how to extend the DataGrid control to add this functionality. One example of such an article is Scott's Creating a Row-Selectable DataGrid Control. Scott's article, and many of the other articles, propose a solution that involves creating a custom ASP.NET server control that extends the DataGrid. This custom server control, then, emits the necessary client-side script to enable to row highlighting functionality. (Specifically, the <tr> HTML elements have onmouseover and onmouseout attributes added...)

While building a custom server control allows for easy deployment and a rich design-time experience, I was determined to come up with a simpler approach to creating a row-highlightable DataGrid, one that would work without requiring any changes to the standard DataGrid control. An idea for how to accomplish this came to me after reading an article about how to create a purely CSS Drop-Down menu on the AListApart website. The concept for that article was simple: Use the CSS hover style to show/hide various nested lists. I was fascinated by the simplicity and pure genius of this concept, and I realized that with a little tweaking, it could be used to highlight the rows of a DataGrid as well.

In this article we'll examine how to utilize the hover feature of CSS to add row highlighting to a standard DataGrid. Feel free to check out the live demo before you begin reading...

- continued -

First Things First: Displaying Data in a DataGrid


Throughout the course of this article I'm going to explain how I used client-side CSS to add row highlighting to a standard DataGrid. In my adventure I bumped up against a number of pitfalls, which I'll point out and show how to avoid. Of course, before we can highlight any of the rows in a DataGrid we need a DataGrid to work with. The code below shows a single page that binds synthetically-created data to a DataGrid, and is the basis for which the final live demo is built around.

<%@ Page Language = "C#" %>
<%@ Import Namespace = "System.Data" %>

<html>
  <head>
    <title>DataGrid Sample</title>
    
    <script runat = "server">
      private void Page_Load(object sender, EventArgs e)
      {
        if (!Page.IsPostBack)
          BindGrid();
      }
      
      private void BindGrid()
      {
        DataTable table = new DataTable("Users");
        table.Columns.Add("firstName");
        table.Columns.Add("lastName");
        table.Columns.Add("emailAddress");
        
        AddRow(table, "Bugs", "Bunny", "bbunny@wb.com");
        AddRow(table, "Mickey", "Mouse", "mmouse@disney.com");
        AddRow(table, "Donald", "Duck", "dduck@disney.com");
        AddRow(table, "Dan", "Marino", "dmarino@dolphins.com");
        AddRow(table, "Steve", "Stchur", "sstchur@yahoo.com");
        
        myGrid.DataSource = new DataView(table);
        myGrid.DataBind();        
      }
      
      private void AddRow(DataTable table, string firstName, 
                          string lastName, string email)
      {
        DataRow row = table.NewRow();
        row["firstName"] = firstName;
        row["lastName"] = lastName;
        row["emailAddress"] = email;
        table.Rows.Add(row);
      }
    </script>
  </head>
    
  <body>
    <asp:DataGrid id = "myGrid"
                  CellPadding = "5"
                  AutoGenerateColumns = "false"
                  Font-Name = "verdana"
                  Font-Size = "10pt"
                  runat = "server">
                  
      <HeaderStyle BackColor = "#336699" 
                 ForeColor = "#ffffff" Font-Bold = "true" />      
      <AlternatingItemStyle BackColor = "#eeeeee" />
                  
      <Columns>
        <asp:BoundColumn HeaderText = "First Name" 
                            DataField = "firstName" />
        <asp:BoundColumn HeaderText = "Last Name" 
                            DataField = "lastName" />
        <asp:BoundColumn HeaderText = "Email" 
                            DataField = "emailAddress" />
      </Columns>
    </asp:DataGrid>
  </body>
</html>
[View a Live Demo!]

At this point we have a very simple DataGrid that is bound to some hard-coded data. As the live demo shows, I've set the HeaderStyle to a nice blue, while the AlternatingItemStyle property specifies that the background color of every other row should be a light gray.

First Attempts at Row Highlighting


My first instinct to make the rows "highlightable" was to simply add a CSS style to any TR (table row) elements on the page like so:

<style type = "text/css">
   tr:hover { background-color: #ffccff; }
</style>

Since each of the rows in a DataGrid is rendered as a <tr> element, my initial thinking was that this CSS would highlight each of the DataGrid's rows pink (#ffccff) when it was moused over. I started by testing this approach with the Firefox Web browser and noted that each row of the DataGrid is highlighted on mouseover. However, every row of the DataGrid was highlighted, including the DataGrid's Header row. When testing this CSS with Internet Explorer I found that it did not highlight rows at all!

Fixing Row Highlighting for Internet Explorer


A little research turned up the fact that IE only supports :hover for hyperlinks (<a> tags). Fortunately, as it turned out, fixing this was fairly easy to remedy with some JavaScript and a slight modification to the CSS stylesheet. Essentially I defined a tr-level class, over and used the same CSS as with the :hover. The CSS stylesheet, then, becomes:

<style type = "text/css">
   tr:hover, tr.over { background-color: #ffccff; }
</style>

That change of course, won't solve the problem by itself since we've yet to indicate that the <tr> elements of the DataGrid belong to the over class. A little JavaScript is needed to set the class attribute of each <tr> element to over when it's moused over:

<script language = "javascript">    
  startHighlight = function()
  {
    if (document.all && document.getElementById)
    {  
      navRoot = document.getElementById(ID of DataGrid);
      
      // Get a reference to the TBODY element 
      tbody = navRoot.childNodes[0];
      
      for (i = 0; i < tbody.childNodes.length; i++)
      {
        node = tbody.childNodes[i];
        if (node.nodeName == "TR")
        {
          node.onmouseover=function()
          {
            this.className = "over";                
          }
          
          node.onmouseout=function()
          {
            this.className = this.className.replace("over", "");
          }
        }
      }
    }
  }
  
  window.onload = startHighlight;      
</script>
[View a Live Demo!]

The above script tells the browser to start searching through all child elements of the DataGrid. (Note: you need to replace ID of DataGrid with the client-side ID of the <table> control that is rendered from the DataGrid. Unless the DataGrid is within a User Control, another DataGrid, or some other naming container, it will simply be the same as the ID property of the DataGrid Web control.) When the script finds a DataGrid element whose node name is TR it adds an onmouseover function and an onmouseout function. The purpose of each of those functions is to simply set the CSS class of the <tr> to over or to nothing, depending on if the mouse is being moved over the <tr> or out of it.

If you test this code out in IE now, you'll notice something odd. Every OTHER row highlights. Why? Because we specifically told our DataGrid to that each AlternatingItemStyle should have a background color of #eeeeee. Since ASP.NET renders that style inline, it take precedence over the CSS class that we specify in JavaScript. In fact, had we specified an ItemStyle as well, we'd see that none of the rows highlight for this very same reason.

So how do we get around this issue? Simple. Just specify that when a TR is moused over, any TD elements (that are children of that TR) get the CSS class "over" attached to them. This works, because any styles set to the TD element will override those of its parent (the TR element). Here is the updated CSS.

<style type = "text/css">
   tr:hover, tr.over td { background-color: #ffccff; }
</style>

Not Highlighting the Header Row


Ok, so we've solved the IE-specific problem, but there is still the issue of the highlighting HeaderRow. What to do, what to do. Well, a keen reader might notice that in IE, the Javascript is looping through every single row in the table (DataGrid). An easy solution to our problem in IE then, is to simply start at row 1, rather that at row 0, thereby skipping the first row (the Header row):

// In the startHighlight function...
for (i = 1; i < tbody.childNodes.length; i++)
{
    // this code stays the same
}
[View a Live Demo!]

Give that a go in IE, and you'll see that the Header row is no longer "lighting" up when moused over; also, thanks to our addition of the td in the CSS stylesheet, all of the DataGrid's rows are highlighting in IE, not just the alternating ones.

So what do we do about Firefox (and other non-IE browsers)? What we need is a way to tell the browser that only certain TR elements should have the hover style applied to them. Fortunately, CSS makes this fairly easy. Something like this should do the trick:

<style type = "text/css">
   tr.row:hover, tr.over td { background-color: #ffccff; }
</style>

The above CSS tells the browser to only apply the hover style to those TR elements whose CSS class is row.

Why Use Two Techniques?
I have employed two different techniques for enabling row highlighting in a DataGrid, the technique used being based on the visitor's browser: pure CSS for FireFox, a mix of CSS and JavaScript for IE. It's a bit unfortunate that we have to use two different techniques to support the two most popular browsers. One option would be to tailor the JavaScript code so that it would also work with FireFox.

I contemplated this approach, however I'm a believer in CSS, and I feel like it is the superior approach (i.e., the Right Way to do it). I consider the Javascript a bit of a hack. So my attitude is, let's do it "the right way" whenever possible, and only resort to Javascript when we have to. You are more than welcome to tweak the JavaScript so that it works with FireFox if you'd like, but my particular personal philosophy predicates that I persist with this path.

As it stands right now, this won't work, because the TR elements in our DataGrid don't have any CSS class associated with them. We can fix that by specifying the CssClass property in the AlternatingItemStyle and ItemStyle sections in our DataGrid:

<AlternatingItemStyle BackColor = "#eeeeee" CssClass = "row" />
<ItemStyle BackColor = "#ffffff" CssClass = "row" />
[View a Live Demo!]

Conclusion


And there you have it! A easy way to highlight the rows in a DataGrid that uses considerably less code that some of the other methods you may have seen / implemented. One important thing I should point out, is that I've only tested this in IE 6.0 and Mozilla Firefox 1.0. I'm not sure how this will react in other browsers (though I suspect Netscape 7 and IE 5.5) should handle it fairly well. In any case, if you find it doesn't work in some other browser, the Javascript is yours for the taking. Simply modify it to suit your needs and you're good to go.

One final thing I'd like to mention is that I cannot take credit for JavaScript in this article. I modified it some, but the bulk of it came from Patrick Griffiths' and Dan Webb's article Suckerfish Dropdown on AListApart.Com. I definitely recommend checking out that article as it will provide you with some extremely valuable CSS insight.

Happy Programming!

  • By Steve Stchur



  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article