Displaying hierarchical data is a common feature practiced by many websites. Hierarchical data can be displayed in many different ways. In this article we will learn how to display nested data using nested GridView controls.

Introduction:

Displaying hierarchical data is a common feature practiced by many websites. Hierarchical data can be displayed in many different ways. In this article we will learn how to display nested data using nested GridView controls.

The Domain Model:

The domain model is really simple and consists of two entities, Category and Products. A single category can have multiple products hence producing the one-to-many relationship. This article does not contain any persistent storage like database or xml files and the entities are populated at runtime.

Populating the Entities:

Since, we are not using any database we need to populate the entities manually. This can easily be accomplished by using nested for loops. Take a look at the code below which creates several categories and adds few products to each of the category.

private List<Category> _categories = new List<Category>();
private List<Category> GetCategories()
        {
           _categories = new List<Category>();

            for (int i = 1; i <= 20; i++)
            {
                Category category = new Category();
                category.Id = i;
                category.Name = String.Format("Category {0}", i);

                for (int j = 1; j <= 3; j++)
                {
                    Product product = new Product();
                    product.Id = j;
                    product.Name = String.Format("Product {0} of Category {1}", j,i);

                    category.Products.Add(product);
                }

                _categories.Add(category);
            }

            return _categories;
        }

In the code above we are simply creating some dummy categories and adding dummy products to each category.
The BindData method is responsible for binding the categories to the GridView control.

private void BindData()
        {
            gvCategories.DataSource = GetCategories();
            gvCategories.DataBind();
        }

The GridView will look something like this: 

Displaying the Products GridView as a Child GridView:

To display products GridView as a child GridView we need to add it to the ItemTemplate of the categories GridView. Check out the code below which shows the products GridView added to the Categories GridView.

<asp:GridView ID="gvCategories" CssClass="grid" GridLines="none" runat="server" AutoGenerateColumns="false">
   
    <Columns>
   
    <asp:TemplateField HeaderText="Category Name">
    <ItemTemplate>  
   
   <%# Eval("Name") %>
   
    <asp:GridView CssClass="innerGrid" GridLines="None" ID="gvProducts" runat="server" AutoGenerateColumns="False" DataSource='<%# Eval("Products") %>' CellPadding="4" DataSourceID="" ForeColor="#333333">   
    <Columns>
      
    <asp:TemplateField>
   
    <ItemTemplate>
   
    <%# Eval("Name") %>
   
    </ItemTemplate> 
   
    </asp:TemplateField>
    </Columns>
    </asp:GridView>
   
   
</ItemTemplate>   
    </asp:TemplateField>
   
    </Columns>
   
    </asp:GridView> 

And here it the result: 


 
So, now we can see the child products under each category. Although this is what we were after but this does not look good. We need to add some behavior so that we can expand and collapse the products.

Creating Expand and Collapse Functionality:

We will be using a “+” sign image to expand and “-“ sign image to collapse the products GridView. To write minimal code we will be leveraging the power of the Prototype JavaScript Library. You are free to use any library that you desire.
Let’s first add the “+” sign to our products GridView. Check out the following code:

<asp:GridView ID="gvCategories" CssClass="grid" GridLines="none" runat="server" AutoGenerateColumns="false">
   
    <Columns>
   
    <asp:TemplateField HeaderText="Category Name">
    <ItemTemplate>  
   
   <a id="openCloseLink" onclick="toggleDetailsView(this)" href="#">
    <img src="tn_plus.GIF" style="border: 0px;" alt="PLUS" />
    </a>
   
    <span class="mainTitleStyle">
    <%# Eval("Name") %>
   </span>
   
    <asp:GridView CssClass="innerGrid" GridLines="None" ID="gvProducts" runat="server" AutoGenerateColumns="False" DataSource='<%# Eval("Products") %>' CellPadding="4" DataSourceID="" ForeColor="#333333">   
    <Columns>
      
    <asp:TemplateField>
   
    <ItemTemplate>
   
    <%# Eval("Name") %>
   
    </ItemTemplate> 
   
    </asp:TemplateField>
    </Columns>
    </asp:GridView>
   
    </ItemTemplate>   
    </asp:TemplateField>
   
    </Columns>
   
    </asp:GridView>
And here is the result:
 
Now, we need some way to hide the products GridView. This is achieved by adding a simple “DIV” tag.

<div id="divDetailsView" runat="server" class="collapsed">
// Products GridView
</div>

The class “collapsed” is responsible for hiding the “DIV” element which in turn hides the contained GridView control.  Check out the effect below: 


This is much better! Now, the user can see all the categories collapsed and can decide which one to expand.
Wait! It is not over yet. We still need to implement the JavaScript functions which trigger the show and hide of the products GridView.

Client Side Implementation to Toggle Nested GridView:

The toggleDetailsView function is responsible for collapsing and expanding the nested products GridView.

var className = 'collapsed';   
function toggleDetailsView(link)
{
    // change HTML text to open and close
   
    var img = $(link).childElements()[0];    
       
    var imgFileName = getFileNameFromUrl(img.src);
   
    img.src = imgFileName == 'tn_plus.GIF' ? 'tn_minus.GIF' : 'tn_plus.GIF';    
            
    var element = $(link).next("." + className);    
   
    $(element).toggleClassName('expanded');
   
}

First, we get the image element which is contained as a child of the anchor element. The getFileNameFromUrl function is used to get only the file name from the image URL. After we get the file name we simply toggle the image between “tn_plus.GIF” and “tn_minus.GIF”.  The line var element = $(link).next("." + className); gets the element which has the class name “collapsed”. Finally, the Prototype.js method toggleClassName is used to toggle the class between “collapsed” and “expanded”.

Conclusion:

In this article we learned how to display nested data using nested GridView. We also implemented a nice toggle effect which enabled the users to expand and collapse the child items.

[Download Sample]