Building a grouping Grid with GridView and JQuery

by mosessaur| 08 March 2008| 21 Comments

Nothing really new on this post, just another way to implement mater/detail representation with nested GridViews with assistance of JQuery. Previously I posted about building same feature using ASP.NET AJAX CollapsiblePanel Extender. that was another example of what Matt Berseth presented in his post about building a grouping grid using ASP.NET 3.5 ListView and Linq.

In this post I'll show how same feature can be implemented using JQuery. Very simple and straight forward.

Requirements:
It is required to download latest version of JQueryin order to be able to use this sample [View Demo].

Implementation:
I've created a new ASP.NET AJAX enabled web site using Visual Studio. And I added a script reference to my script manager:

   1: <asp:ScriptManager ID="ScriptManager1" runat="server" >
   2:     <Scripts>
   3:         <asp:ScriptReference Path="~/scripts/jquery-1.2.3.min.js" ScriptMode="Release" />
   4:     </Scripts>
   5: </asp:ScriptManager>

Using same design I made on my previous post, I started to implement the usage of JQuery. I used JQuery to replace the functioanlity provided by CollapsiblePanelExtender.

JQuery has a method called slideToggle, I used this method to expand and collapse the details grid. Below is the JavaScript method used to handle expand and collapse:

   1: <script type="text/javascript">
   2:     //master: id of div element that contains the information about master data
   3:     //details: id of div element wrapping the details grid
   4:     function showhide(master,detail)
   5:     { 
   6:         //First child of master div is the image
   7:         var src = $(master).children()[0].src;
   8:         //Switch image from (+) to (-) or vice versa.
   9:         if(src.endsWith("plus.png"))
  10:             src = src.replace('plus.png','minus.png');
  11:         else
  12:             src = src.replace('minus.png','plus.png');
  13:         
  14:         //Set new image
  15:         $(master).children()[0].src = src;
  16:         
  17:         //Toggle expand/collapse                   
  18:         $(detail).slideToggle("normal");             
  19:     }
  20: </script>

Both master and details parameters mentioned in the code above, is ID of a DIV element with leading '#' -related to JQuery Syntax-. Those DIV elements are used to wrap both master data and details data:

   1: <div class="group" id='<%#String.Format("customer{0}",Container.DataItemIndex) %>' onclick='showhide(<%#String.Format("\"#customer{0}\"",Container.DataItemIndex) %>,<%#String.Format("\"#order{0}\"",Container.DataItemIndex) %>)'>
   2: ......<!--Master Data-->
   3: </div>
   1: <div id='<%#String.Format("order{0}",Container.DataItemIndex) %>' class="order">
   2: ....<!--Details Data-->
   3: </div>

When you click on first DIV, collapse/expand image will switch, and the second DIV wil toggel its state (collapse/expand). Same thing can be applied to Matt's sample using JQuery.

Download the attached sample to review the code.

kick it on DotNetKicks.com

Comments (21) -

FUBAR
FUBAR Indonesia on 3/25/2008 5:24 AM Great job !!
mosessaur
mosessaur Egypt on 3/25/2008 6:35 AM Thank you so much Fubar!
Ayman Islam
Ayman Islam Egypt on 4/1/2008 7:48 PM Thanx alot for the great tutorials, by the way we know each other in real life we met a couple of times before
thanx again
mosessaur
mosessaur Egypt on 4/2/2008 4:25 PM Thank you so much Ayman! I would like to know when and where we met Smile You can see my picture but I am not able to see yours ;) .
Thank you again brother.
Ziyad
Ziyad United States on 8/8/2008 10:34 AM Try this free control for gridview with grouping..
znetcontrols.blogspot.com/.../...pnet-20-with.html
Randall
Randall United States on 10/2/2008 10:14 PM Great article and implementation.  One question - is there any way to make the grid load with all the nodes expanded?
mosessaur
mosessaur Egypt on 10/4/2008 6:29 AM @Randall Yes sure this can be done, and with jQuery it would be very simple. I would provide that soon.
Moustapha
Moustapha United States on 10/4/2008 6:56 AM Thank you for the nice work!
It would be nice if you can apply this to Matt's example. I have tried but when I load the page all of the rows are in the repeater are showing.

I am using a repeater instead of a second grid view
   <div id='<%#String.Format("detail{0}",Container.DataItemIndex) %>' class="order">
                    
                     <asp:Repeater ID="MultipleAddressRepeater"  onitemcommand="MultipleAddressRepeater_ItemCommand"  runat="server" DataSource='<%# GetDataFromView(DataBinder.Eval(Container.DataItem, "EntityID").ToString())%>'
                                        >                                                
                                        <ItemTemplate>                                                    
                                            <div class="AddressRow">
                                                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                                                <%# Eval("MyPlace") %><br />
                                                
                                                <%# Eval("MyIngot2") %>,&nbsp;<%# Eval("State") %>&nbsp;<%# Eval("MyInfo1") %>
                                            </div>
                                        </ItemTemplate>                                                                                              
                                    </asp:Repeater>
                     </div>

Salam
Moustapha
Moustapha United States on 10/4/2008 8:12 AM I was able to make the solution work. thank you.
Prashanth
Prashanth India on 10/22/2008 10:57 AM Thank you very much for the gr8 article.
   Will you please confirm in Jquery is it loading on demand.
As i can see the performance with jquery is very good compare to Matt's same example.

Thanks and Regards,
Prashanth Kumar G.
mosessaur
mosessaur Egypt on 10/22/2008 2:29 PM @Prashanth
I talked about ondemand loading using jQuery AJAX on another post, check it out if that what you want:
mosesofegypt.net/.../...own-Using-jQuery-AJAX.aspx
alek
alek Republic of the Philippines on 10/31/2008 1:19 AM hi!
thanks for this great article,using jquery is much faster than using
ajaxToolkit:CollapsiblePanelExtender,i just compare your two example.
Adam
Adam United States on 12/25/2008 9:30 PM Is it possible to get this in ZIP format im having a heck of a time trying to get .rar to do anything. Also I'm assuming you dont actualy need to be using an Ajax enabled page to do this? Just reference the script? Thanks in advance.
Adam
Adam United States on 12/27/2008 12:39 AM Ignore my previous post I got it to work, still working on display format but very nice so far thanks a bunch.
Adam
Adam United States on 1/5/2009 3:17 PM I was wondering if there would be a easy way to capture what areas have been expanded in order to export to an excel document? I can handle the export if I can build the table, but what I dont know how to do is capture I am assuming in javascript which records have been expanded to do my query so that I can export the data. Any ideas?
Jason S.
Jason S. United States on 1/18/2009 2:55 AM Hey, thanks for some great code and documentation.  Can you show how you can do this with Headers (ShowHeader="true") in the parent?  The only thing I was able to do was create a table, but the headers get repeated that way.   When I've tried to add headers for each column it breaks.  
Jason S.
Jason S. United States on 1/20/2009 10:14 PM Nevermind...I managed to make it work (although I couldn't use Boundfield in the parent grid)  I had to make a Header like so...

<HeaderTemplate></th><th scope="col">Interaction #</th><th scope="col">Member Name</th><th scope="col">Teller<th scope="col">Branch<th scope="col">Date Entered<th scope="col">Event<th scope="col">Event Type</HeaderTemplate>

After that, I used <ItemTemplate> and followed the part in your code which has the plus sign with a bunch of <TD> tags where I included either <asp:Hyperlink> or <asp:Label> tags for each Eval (I needed to manipulate some of the data as well).  I finished that off with </td></tr><tr><td colspan="thenumber of total columns in the parent">  After which I inserted the code for the child grid and it came out perfectly.  
krzycho
krzycho on 4/9/2009 8:28 AM Did you tray use any other controll which this method?

When I put simple button to page and do postback (even if its partial postback from another updatepanel) grids are stop expanding. Frown

Is there any simple solution for that?


Nauman
Nauman United States on 5/4/2009 1:29 PM Is there a way we can keep the expanded row expanded on postbacks, i.e. if i expand a row of urs demo, and then move to back and forth in the pages, the row i expanded get collapsed, i need to keep it expanded on postbacks
mosessaur
mosessaur Egypt on 5/4/2009 5:32 PM Have a look at this post:
mosesofegypt.net/.../...blePanelExtenderPart1.aspx
madval
madval Mexico on 6/10/2009 11:50 AM Moses, thanks for your articles, I just began to learn jQuery and MS AJAX with ASP.NET. I made a little modification to your example to  avoid the onclick='showhide(<%... on div elements, I have my JS on an external file which is referenced in the scriptmanager:

[code]
//master: id del div que contiene la información acerca del grid maestro
//detail: id del div que envuelve al grid de detalle
function showhide(master, detail) {
    //el primer hijo del div master es la imagen
    var src = $('#' + master).children()[0].src;
    //intercambiar imagen de (+) a (-) o viceversa
    if (src.endsWith("plus.png"))
        src = src.replace('plus.png', 'minus.png');
    else
        src = src.replace('minus.png', 'plus.png');
    //establecer la nueva imagen
    $('#' + master).children()[0].src = src;
    //flip/flop para expandir/contraer
    $('#' + detail).slideToggle("normal");
}

//al cargarse el documento
$(document).ready(function() {
    //agregar un click handler a los div's con clase group
    $('div.group').click(function() {
        //id del div master
        var idMaster = this.id;
        //obtenemos el primer hermano, que sea div y tenga clase order, y tomamos su id
        var idDetail = $(this).siblings('div.order')[0].id;
        //llamar la función para mostrar/ocultar el grid de detalle
        showhide(idMaster, idDetail);
    });
});
[/code]
Comments are closed