Wednesday 27 June 2012

Hierarchical GridView in ASP.NET with AJAX, JQuery implementation - Part 2

In previous post, we had seen how to show GridView in hierarchical design such as parent and child relationship. So There will be a parent grid show on the screen when loading the page, to show the details of a particular row the user required to click an expand icon located on the corresponding row. The details of the particular row will show just below the row. The same will repeat for all the rows in the parent Grid.

There are lots of ways to achieve this concept with ASP.NET. I had blogged some of the concept in previous posts. The links are follows –

Hierarchical GridView in ASP.NET
Hierarchical GridView in ASP.NET with AJAX, Javascript implementation
Hierarchical GridView in ASP.NET with AJAX, JQuery implementation - Part 1

In previous post, I had given implementation using JQuery and AJAX concept. As the implementation is using AJAX, it will be very useful when large amount of child records required to be fetched for each row and bind to the grid. So, When clicking the expand icon on the parent Grid, the child Grid View will be created on demand by fetching the records from database and the rest of the records child grids rows are not been fetched from the database.

The problem when using AJAX implementation is the child Grid View will not have any edit functionality on the records in a normal way we do with Grid View. Normally when using a Grid View, some developer gives facility to edit the records with the Grid View itself. So the user can click the Edit link which will make a particular row in edit mode. The user can then provide new data to the rows and save by pressing Save link or cancel the update function using Cancel link. But, when using AJAX implementation for implementing hierarchical Grid View, the child Grid View html source are fetched from another ASPX page using AJAX call and show on the main page inside a DIV. So any server event won’t be able to run with the Child Grid.

To achieve any functionality on the Child Grid such as editing a particular record, we have to use AJAX implementation only. That means, we need to user Java Script or JQuery only to call the server when any event to fire on the server.

I am taking the same example in this post and implementing the following use case.

  1. The page should show a Grid View with list of Orders and Expand icon on the first column.
  2. On click of expand icon on each row, the Order Details of the Order must be fetched from the database and show in the Grid View just below to the row with little adjacent to the first column.
  3. The child Grid View must fetch from the server only on demand to avoid the loading time using AJAX concept.
  4. Once the expand icon clicked, there should be a loading message to inform to the user the details are fetching from the server.
  5. Once the Grid View fetched from the server, the Child Grid should show by hiding the loading message and the expand icon must be changed to collapse icon.
  6. On click of collapse icon, the child grid should hide from the screen.
  7. When the user clicks the Expand icon which was already done before, there should not be a call to the server again for fetching the same details. The system should show the hidden Grid View done in Step 6.
  8. When user moving one page to another page by expanding and collapsing some records and come back to the old pages, the expanded records must be expanded and others are collapsed (means old state must be maintained).
  9. When the child grid shows it should have a column with button, which can be used for editing the particular row.
  10. When the user clicks Edit button, there should be a popup window with list of controls for updating new values. The form should also have Save and Cancel button.
  11. When the user press Save button, the record should be saved to the database and refresh the particular child grid.
  12. When the user press Cancel button, the form should be hidden to continue normal process.

For implementing this requirement, I am using the same code which was posted in last post and enhancing with editing the child Grid View row.

To save the record from the popup screen, there is no .NET server event could be called as the controls are created for the client side (without runat=server). So I am using AJAX concept only for getting the information for a particular record and to save the particular record on the database.

There are multiple ways we can call server method from the client side. Some of the ways are shown in below links.

In this implementation I am planning to use HTTP Handler (GenericHander) method.

The implementation follows –

I have two pages Default.aspx and ChildGridBuilder.aspx.
  1. The Default.aspx page shows the list of Orders on the page. The end user accessing this page only from the browser.
  2. When the user clicking the Expand icon on any of the order row, it will call the ChildGridBuilder.aspx page with Order Id in the query string as parameter using AJAX.
  3. The ChildGridBuilder.aspx page will bind the required records to the GridView and return the HTML script to the Default.aspx page as response to the AJAX call.
  4. The Default.aspx page will show the returned script just below to the Order row expanded inside a DIV control.
The ASPX Script (Default.aspx)
<div id="divHidden">
</div>
<div id="OrderInfoEdit">
    <table style="width:100%">
        <tr>
            <td width="120px">Order Id</td>
            <td><span id="lblOrderId" class="OrderIdInput" /></td>
        </tr>
        <tr>
            <td>Product Name</td>
            <td><span id="lblProductName" class="ProductNameInput" /></td>
        </tr>
        <tr>
            <td>Unit Price</td>
            <td><input id="txtUnitPrice" type="text" style="width:150px" class="UnitPriceInput" /></td>
        </tr>
        <tr>
            <td>Quantity</td>
            <td><input id="txtQuantity" type="text" style="width:150px" class="QuantityInput" /></td>
        </tr>
        <tr>
            <td>Discount</td>
            <td><input id="txtDiscount" type="text" style="width:150px" class="DiscountInput" /></td>
        </tr>
        <tr>
            <td>Amount</td>
            <td><input id="txtAmount" type="text" style="width:150px" class="AmountInput" readonly="readonly" /></td>
        </tr>
        <tr>
            <td colspan="2" style="height:10px">
            <input type="hidden" id="hndProductID" class="ProductIDInput" value="" />
            </td>
        </tr>
        <tr>
            <td colspan="2" style="text-align:center">
                <input type="button" id="btnSave" value="Save" style="width:100px" class="OrderDetailSave" />
                <input type="button" id="btnCancel" class="Cancel" value="Cancel" style="width:100px" />
            </td>
        </tr>
    </table>
</div>
<asp:GridView id="GridViewHierachical" runat="server" AutoGenerateColumns="False"
    Width="100%" DataKeyNames="OrderId" AllowPaging="true" CssClass="GridViewStyle"
    BorderStyle="Solid" PageSize="10" CellPadding="0" CellSpacing="0"
    OnPageIndexChanging="GridViewHierachical_PageIndexChanging" EnableViewState="false">
    <Columns>
        <asp:TemplateField HeaderText="Order ID">
            <ItemStyle Width="10%" />
            <ItemTemplate>
                <input id='hid<%# Eval("OrderID") %>') value='0' type="hidden" />
                <img id="img<%# Eval("OrderID") %>" alt="<%# Eval("OrderID") %>" class="ExpandImage" width="9px" 
                    border="0" src="Images/plus.png" style="cursor:pointer;padding-left:3px;width:12px;height:12px;" />
                <asp:Label ID="lblOrderID" Text='<%# Eval("OrderID") %>' Visible="true" runat="server"></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="CustomerID" HeaderText="Customer ID">
            <ItemStyle Width="10%" />
        </asp:BoundField>
        <asp:BoundField DataField="ShippedDate" HeaderText="Shipped Date"  DataFormatString="{0:MMMM d, yyyy}">
            <ItemStyle Width="20%" />
        </asp:BoundField>
        <asp:BoundField DataField="ShipName" HeaderText="Ship Name">
            <ItemStyle Width="20%" />
        </asp:BoundField>
        <asp:BoundField DataField="ShipCountry" HeaderText="Ship Country">
            <ItemStyle Width="15%" />
        </asp:BoundField>
        <asp:BoundField DataField="ShipCity" HeaderText="Ship City">
            <ItemStyle Width="15%" />
        </asp:BoundField>
        <asp:TemplateField>
            <HeaderStyle CssClass="InvisibleCol" />
            <ItemStyle CssClass="InvisibleCol" />
            <ItemTemplate>
            </td></tr>
                <tr class="ChildRow">
                    <td id="td<%# Eval("OrderID") %>" colspan="6">
                        <div id="div<%# Eval("OrderID") %>" style="width:100%;display:none;">
                            <div style='padding:4px;'>
                                <img src='Images/ajax-loader.gif' alt='' />
                                <span style='color:blue;font-size:17px;font-weight:bold;'>Loading... Please wait</span>
                            </div>
                        </div>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
    <FooterStyle BackColor="#CCCCCC" ForeColor="Black"></FooterStyle>
    <RowStyle CssClass="GridViewRow" Height="24px"></RowStyle>
    <HeaderStyle CssClass="GridViewHeader" Height="22px"></HeaderStyle>
    <SelectedRowStyle BackColor="#008A8C" Font-Bold="True" ForeColor="White"></SelectedRowStyle>
    <PagerStyle BackColor="#999999" ForeColor="Black" HorizontalAlign="Right"></PagerStyle>
    <AlternatingRowStyle CssClass="GridViewAlternativeRow"></AlternatingRowStyle>
</asp:GridView>
<asp:HiddenField ID="hndExpandedChild" runat="server" Value="" />
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
I use JQuery version 1.7.2 in this example
<script src="Scripts/jquery-1.7.2.min.js" type="text/javascript"></script>
The Code behind Script (Default.aspx.cs)
protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        BindGrid();
    }
}
private void BindGrid()
{
    using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString))
    {
        string strSQL = "SELECT Orders.OrderID, Orders.CustomerID, Orders.ShippedDate, Orders.ShipName, Orders.ShipCountry, Orders.ShipCity FROM Orders";
        SqlCommand command = new SqlCommand(strSQL, connection);
        command.CommandType = CommandType.Text;

        connection.Open();
        SqlDataReader dr = command.ExecuteReader(CommandBehavior.CloseConnection);

        IList<Order> orderList = new List<Order>();
        while (dr.Read())
        {
            Order order = new Order();
            order.OrderID = Convert.ToInt32(dr["OrderID"].ToString());
            order.CustomerID = dr["CustomerID"].ToString();
            order.ShippedDate = dr["ShippedDate"].ToString();
            order.ShipName = dr["ShipName"].ToString();
            order.ShipCountry = dr["ShipCountry"].ToString();
            order.ShipCity = dr["ShipCity"].ToString();

            orderList.Add(order);
        }
        GridViewHierachical.DataSource = orderList;
        GridViewHierachical.DataBind();
    }
}

protected void GridViewHierachical_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
    GridViewHierachical.PageIndex = e.NewPageIndex;
    BindGrid();
}

protected void Button1_Click(object sender, EventArgs e)
{

}
The Order entity class (Order.cs)
public class Order
{
    public int OrderID { get; set; }
    public string CustomerID { get; set; }
    public string ShippedDate { get; set; }
    public string ShipName { get; set; }
    public string ShipCountry { get; set; }
    public string ShipCity { get; set; }
}
The ASPX script (ChildGridBuilder.aspx)
<asp:GridView id="GridViewDetails" runat="server" 
    AllowSorting="false" AutoGenerateColumns="False" Width="100%"
    CellSpacing="1" CellPadding="0" GridLines="Both" DataKeyNames="OrderId"
    BackColor="White" BorderWidth="2px" BorderStyle="Ridge"
    BorderColor="White" AllowPaging="false" ForeColor="#000066">
    <Columns>
        <asp:BoundField DataField="OrderId" HeaderText="Order ID">
            <ItemStyle Width="10%" />
        </asp:BoundField>
        <asp:BoundField DataField="ProductName" HeaderText="Product Name">
            <ItemStyle Width="30%" />
        </asp:BoundField>
        <asp:BoundField DataField="UnitPrice" HeaderText="Unit Price" DataFormatString="{0:N}" ItemStyle-HorizontalAlign="Right">
            <ItemStyle Width="15%" />
        </asp:BoundField>
        <asp:BoundField DataField="Quantity" HeaderText="Quantity" DataFormatString="{0:N}" ItemStyle-HorizontalAlign="Right">
            <ItemStyle Width="15%" />
        </asp:BoundField>
        <asp:BoundField DataField="Discount" HeaderText="Discount" DataFormatString="{0:N}" ItemStyle-HorizontalAlign="Right">
            <ItemStyle Width="15%" />
        </asp:BoundField>
        <asp:BoundField DataField="Amount" HeaderText="Amount" DataFormatString="{0:N}" ItemStyle-HorizontalAlign="Right">
            <ItemStyle Width="15%" />
        </asp:BoundField>
        <asp:TemplateField HeaderText="Edit">
            <ItemStyle Width="40%" />
            <ItemTemplate>
                <input id="btnOrderID" class="OrderClass" type="button" value="Edit" onclick="ProductEditClient('<%# Eval("OrderID") %>', '<%# Eval("ProductID") %>')" />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
    <RowStyle ForeColor="#000066" Height="20px"></RowStyle>
    <SelectedRowStyle BackColor="#669999" Font-Bold="True" ForeColor="White"></SelectedRowStyle>
    <PagerStyle BackColor="White" ForeColor="#000066" HorizontalAlign="Left"></PagerStyle>
    <HeaderStyle CssClass="GridViewHeader"></HeaderStyle>
    <AlternatingRowStyle BorderStyle="Solid" BorderWidth="0px"></AlternatingRowStyle>
</asp:GridView>
The Code behind Script (ChildGridBuilder.aspx.cs)
protected void Page_Load(object sender, EventArgs e)
{
    Response.Clear();
    Response.ContentType = "text/xml";
    BindGrid();

    System.IO.StringWriter stringWrite = new System.IO.StringWriter();
    System.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);
    GridViewDetails.RenderControl(htmlWrite);
    Response.Write(stringWrite.ToString());
            
    Response.End();
}
public override void VerifyRenderingInServerForm(Control control)
{
}
private void BindGrid()
{
    // I am delaying the response to see the Loading... message
    System.Threading.Thread.Sleep(1000);

    using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString))
    {
        string strSQL = "SELECT OrderDetails.OrderID, OrderDetails.ProductID, Products.ProductName," +
                                      "OrderDetails.UnitPrice, OrderDetails.Quantity, OrderDetails.Discount, " +
                                      "((OrderDetails.UnitPrice * OrderDetails.Quantity) - OrderDetails.Discount) Amount " +
                                            "FROM [Order Details] OrderDetails " +
                                            "JOIN Products ON Products.ProductID = OrderDetails.ProductID " +
                                            "WHERE OrderDetails.OrderID = '" + Request.QueryString["OrderID"].ToString() + "'";
        SqlCommand command = new SqlCommand(strSQL, connection);
        command.CommandType = CommandType.Text;

        connection.Open();
        SqlDataReader dr = command.ExecuteReader(CommandBehavior.CloseConnection);

        IList<OrderDetails> detailsList = new List<OrderDetails>();
        while (dr.Read())
        {
            OrderDetails details = new OrderDetails();
            details.OrderID = Convert.ToInt32(dr["OrderID"].ToString());
            details.ProductID = Convert.ToInt32(dr["ProductID"].ToString());
            details.ProductName = dr["ProductName"].ToString();
            details.UnitPrice = Convert.ToDouble(dr["UnitPrice"].ToString());
            details.Quantity = Convert.ToInt32(dr["Quantity"].ToString());
            details.Discount = Convert.ToDouble(dr["Discount"].ToString());
            details.Amount = Convert.ToDouble(dr["Amount"].ToString());

            detailsList.Add(details);
        }

        GridViewDetails.DataSource = detailsList;
        GridViewDetails.DataBind();
    }
}
The OrderDetails entity class (OrderDetails.cs)
public class OrderDetails
{
    public int OrderID { get; set; }
    public int ProductID { get; set; }
    public string ProductName { get; set; }
    public double UnitPrice { get; set; }
    public int Quantity { get; set; }
    public double Discount { get; set; }
    public double Amount { get; set; }
}
I use GenericHandler for getting a particular order details to show on the popup screen and to save the same information in the database. So add a GenericHandler (GetOrderData.ashx) file and add the following code.
The GetOrderData.ashx code (GetOrderData.ashx.cs)
public void ProcessRequest(HttpContext context)
{
    context.Response.ContentType = "text/plain";

    try
    {
        if (context.Request.Form["Type"] == "GET")
        {
            OrderDetails details = new OrderDetails();
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString))
            {
                string strSQL = "select OrderDetails.OrderID, OrderDetails.ProductID, OrderDetails.UnitPrice, OrderDetails.Quantity, OrderDetails.Discount, Products.ProductName, ((OrderDetails.UnitPrice * OrderDetails.Quantity) - OrderDetails.Discount) Amount from [Order Details] OrderDetails JOIN Products ON Products.ProductID = OrderDetails.ProductID Where OrderDetails.OrderID = " + context.Request.Form["OrderID"].ToString() + " And OrderDetails.ProductID = " + context.Request.Form["ProductID"].ToString();
                SqlCommand command = new SqlCommand(strSQL, connection);
                command.CommandType = CommandType.Text;

                connection.Open();
                SqlDataReader dr = command.ExecuteReader(CommandBehavior.CloseConnection);

                while (dr.Read())
                {
                    details.OrderID = Convert.ToInt32(dr["OrderID"].ToString());
                    details.ProductID = Convert.ToInt32(dr["ProductID"].ToString());
                    details.ProductName = dr["ProductName"].ToString();
                    details.UnitPrice = Convert.ToDouble(dr["UnitPrice"].ToString());
                    details.Quantity = Convert.ToInt32(dr["Quantity"].ToString());
                    details.Discount = Convert.ToDouble(dr["Discount"].ToString());
                    details.Amount = Convert.ToDouble(dr["Amount"].ToString());
                }
            }
            System.Web.Script.Serialization.JavaScriptSerializer objSerializer =
                    new System.Web.Script.Serialization.JavaScriptSerializer();

            context.Response.Write(objSerializer.Serialize(details));
        }
        else
        {
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString))
            {
                string strSQL = "Update [Order Details] Set UnitPrice = '" + context.Request.Form["UnitPrice"].ToString() + "', " +
                                                        " Quantity = '" + context.Request.Form["Quantity"].ToString() + "', " +
                                                        " Discount = '" + context.Request.Form["Discount"].ToString() + "' " +
                                                        " Where OrderID = " + context.Request.Form["OrderID"].ToString() + " " +
                                                        " And ProductID = " + context.Request.Form["ProductID"].ToString();

                SqlCommand command = new SqlCommand(strSQL, connection);

                connection.Open();

                context.Response.Write(command.ExecuteNonQuery());
            }
        }
    }
    catch (Exception ex)
    {
        context.Response.Write("error");
    }
}
The Style Sheet
.GridViewStyle
{
    font-family:Calibri;
    font-size:15px;
}
.GridViewHeader
{
    background: url(../../Images/header.png) repeat-x 0px 0px;
}
.GridViewRow
{
}
.GridViewAlternativeRow
{
    background-color:#edf5ff;
}
.InvisibleCol
{
    display:none;
}
.ChildRow
{
    border-width:0px;
}

/* Style */
#divHidden
{
 width: 100%;
 height:100%;
 background-color:Gray;
 background: url(../../Images/hidden.png) repeat;
 position: absolute;
 top: 0;
 left: 0;
 z-index: 100;
 display: none;
}

.EditInfo
{
    width: 310px;
 height: 220px;
 background-color: White;
 position: absolute;
 left: 50%;
 top: 50%;
 margin-top: -50px;
 margin-left: -168px;
 vertical-align:middle;
 z-index: 1001;
 display: none;
}
#OrderInfoEdit
{
 width: 400px;
 height: 190px;
 background-color: White;
 position: absolute;
 left: 35%;
 top: 35%;
 margin-top: -50px;
 margin-left: -168px;
 vertical-align:middle;
 z-index: 1001;
 display: none;
 border: 1px solid blue;
 margin: 2px;
 padding: 10px;
}
#OrderInfoEdit P
{
 width: 85%;
 margin: 10px auto;
 text-align: left;
}
#OrderInfoEdit P.button
{
 padding-top: 10px;
 border-top: 1px solid #D1D1D1;
}
The JQuery code
$(document).ready(function () {

    if ($('#<%= hndExpandedChild.ClientID %>').val().length > 0) {

        // Will run when some child grids are expanded
        $.each($('#<%= hndExpandedChild.ClientID %>').val().split(","), function (index, value) {
            ExpandCollapse(value);
        });
    }

    $('.ExpandImage').click(function () {

        ExpandCollapse($(this).attr('alt'));

    })
    function ExpandCollapse(orderId) {

        if ($('#div' + orderId)) {

            // Is already ChildGrid shown. If not shown
            if (!isDisplayed($('#div' + orderId))) {

                if ($('#hid' + orderId).val() == '0') {

                    $('#div' + orderId).css("display", "block");
                    $.ajax({
                        url: 'ChildGridBuilder.aspx?datetime=' + new Date().getTime(),
                        type: 'GET',
                        data: "OrderID=" + encodeURIComponent(orderId),
                        dataType: "html",
                        success: function (response) {
                            $('#div' + orderId).html(response);
                            $('#div' + orderId).css("display", "block");
                            $('#img' + orderId).attr('src', 'images/minus.png');
                            $('#hid' + orderId).val("1");
                        },
                        error: function (xhr, ajaxOptions, thrownError) {
                            alert('Error Occured!');
                            $('#div' + orderId).css("display", "none");
                        }
                    });
                }
                else {
                    $('#div' + orderId).css("display", "block");
                    $('#img' + orderId).attr('src', 'images/minus.png');
                }

                var selectedIds = "," + $('#<%= hndExpandedChild.ClientID %>').val() + ",";
                if (selectedIds.indexOf("," + orderId + ",") == -1) {
                    selectedIds += "," + orderId;

                    selectedIds = selectedIds.replace(/,,/g, ","); // Replacing all ,, ,,, ,,,, etc., to ,
                    while (selectedIds.substring(0, 1) == ",") selectedIds = selectedIds.substring(1);

                    $('#<%= hndExpandedChild.ClientID %>').val(selectedIds);
                }
            }
            else { // Already Child Grid Shown
                $('#div' + orderId).css("display", "none");
                $('#img' + orderId).attr('src', 'images/plus.png');

                var selectedIds = "," + $('#<%= hndExpandedChild.ClientID %>').val() + ",";

                if (selectedIds.indexOf("," + orderId + ",") >= 0) {

                    selectedIds = selectedIds.replace("," + orderId + ",", ","); // Removing the Id

                    selectedIds = selectedIds.replace(/,,/g, ","); // Replacing all ,, ,,, ,,,, etc., to ,
                    selectedIds = selectedIds.substr(1, selectedIds.length - 2); // Removing , both the end and assigning

                    $('#<%= hndExpandedChild.ClientID %>').val(selectedIds);
                }
            }
        }
    }
    ProductEditClient = function (orderId, productId) {
        $("#divHidden").css("display", "block");
        $("#OrderInfoEdit").css("display", "block");

        jQuery.post('GetOrderData.ashx',
                    { Type: "GET", OrderID: orderId, ProductID: productId },
                    function (data) {
                        var orderDetails = eval("(" + data + ")");
                        $(".OrderIdInput").text(orderDetails["OrderID"]);
                        $(".ProductNameInput").text(orderDetails["ProductName"]);
                        $(".UnitPriceInput").val(orderDetails["UnitPrice"]);
                        $(".QuantityInput").val(orderDetails["Quantity"]);
                        $(".DiscountInput").val(orderDetails["Discount"]);
                        $(".AmountInput").val(orderDetails["Amount"]);
                        $(".ProductIDInput").val(orderDetails["ProductID"]);
                    })
                    .error(function () {
                        alert('Error Occured!');
                        $('#div' + orderId).css("display", "none");
                    })
    }
    // This function is for cancel button, when click of this button the popup screen will be hidden and show as normal.
    $(".Cancel").click(function () {
        $("#divHidden").css("display", "none");
        $("#OrderInfoEdit").css("display", "none");
    });
    $(".UnitPriceInput").blur(function() {
        $(".AmountInput").val(($(".UnitPriceInput").val() * $(".QuantityInput").val()) - $(".DiscountInput").val());
    });
    $(".QuantityInput").blur(function() {
        $(".AmountInput").val(($(".UnitPriceInput").val() * $(".QuantityInput").val()) - $(".DiscountInput").val());
    });
    $(".DiscountInput").blur(function() {
        $(".AmountInput").val(($(".UnitPriceInput").val() * $(".QuantityInput").val()) - $(".DiscountInput").val());
    });
    $(".OrderDetailSave").click(function () {
        jQuery.post('GetOrderData.ashx',
                    { Type: "SAVE", OrderId: $(".OrderIdInput").text(),
                        ProductID: $(".ProductIDInput").val(),
                        UnitPrice: $(".UnitPriceInput").val(),
                        Quantity: $(".QuantityInput").val(),
                        Discount: $(".DiscountInput").val(),
                        Amount: $(".AmountInput").val(),
                    },
                    function (data) {
                        if (data == 1)
                        {
                            alert("Record Saved Successfully");
                            ExpandCollapse($(".OrderIdInput").text());
                            $('#hid' + $(".OrderIdInput").text()).val('0');
                            ExpandCollapse($(".OrderIdInput").text());
                            $("#divHidden").css("display", "none");
                            $("#OrderInfoEdit").css("display", "none");
                        }
                    })
                    .error(function () {
                        alert('Error Occured!');
                        $('#div' + orderId).css("display", "none");
                    })
    });
    function isDisplayed(object) {
        // if the object is visible return true
        if ($(object).css('display') == 'block') {
            return true;
        }
        // if the object is not visible return false
        return false;
    };
});
Note: When saving the child grid details on the popup, it calls the ExpandCollapse to fetch the new details and overwrite the existing content. Because the AJAX calls are caching the data, that will return the same content. So I have added current time in line # 27 with the url.

The output of the code would be -







download the working example of the source code in C# here and in VB here.


24 Responses to “Hierarchical GridView in ASP.NET with AJAX, JQuery implementation - Part 2”

  • Anonymous says:
    9 July 2012 at 12:27

    Hi! I am interested in reviewing your article. Where can I download the files? Thanks in advance!

  • Thirumalai M says:
    10 July 2012 at 00:00

    Hi, Sorry forgot to attach the source code files. I have done now. Please review it and let me know if you face any issue.

  • Anonymous says:
    13 July 2012 at 06:53

    Thanks for the great article. My team lead wants me to try to do it without the pop up window. The data will be edited just below the child grid instead of the pop up window. I'll check if it is feasible because I'm just a beginner with jQuery. Thanks again!

  • Anonymous says:
    13 July 2012 at 07:57

    Thanks for the great article! It's a big help for a jQuery newbie like me. However, my boss is asking me to try to do it without the pop up window. In short, the child grid has the capability of adding new records and editing the existing ones w/o the pop up.

  • Thirumalai M says:
    13 July 2012 at 10:27

    Hi,

    I posted the code which gives an idea to popup and show the values and save to the database. For adding new records and edit the same without popup still not posted. I will post when I get free time.
    Currently please try to solve by using the code I given. You can mail me if you need any help.

  • Derek Tan says:
    11 August 2012 at 08:19

    Hey Thiru,

    i tested your demo using chrome and firefox, the master grid can load but the child grid is not able to load.

    it just shows "loading... Please Wait"

    Any idea?

  • Thirumalai M says:
    11 August 2012 at 11:10

    For testing, pls verify the code executing the child grid aspx (here ChildGridBuilder.aspx) by making breakpoint in that page. If that is done, check the stringWrite in the page load of child grid.
    If that come perfect, you need to check with by providing alert in the jquery after 28 line after the function as below
    function (data) {alert(data);}
    If the alert shows perfect html code of gridview, then we need to see what could be the other issue.

    You can run the code provided in the post, if this code works it will be easy to debug your code.

  • Anonymous says:
    3 November 2012 at 00:49

    Hello!

    hello, i was testing each step described above, in the JavaScript chrome and firefox do not recognize and do not know why, could you help me? thanks in advance

  • Thirumalai M says:
    5 November 2012 at 17:01

    Hi, I am little busy with my work. Will update you after some days

  • Anonymous says:
    16 January 2013 at 21:04

    I have the same issue Any Updates Dear thiru

  • Thirumalai M says:
    16 January 2013 at 23:51

    Hi, Sorry... forgot to work on this for long time. I too seen in firefox, the busy image not shown. I did some work to show that. I need to elaborate according to this example. I will update you once done. I just returned back after my holidays. So will update in next week sometime.

  • Pangjiu says:
    31 March 2013 at 11:03

    Hi,
    I would like to know how to do filterting and sorting to the Hierarchical GridView? Will filtering also search for the child row data and sorting only parent grid?

    I wish to see your new post on this. Thanks a lot.

  • Thirumalai M says:
    1 April 2013 at 10:53

    Hi, for filtering, please look at the following url -
    http://www.dotnettwitter.com/2012/08/filtering-on-each-column-in-gridview-as.html
    http://www.dotnettwitter.com/2012/08/filtering-on-each-column-in-gridview-as_26.html

    Here, the selected values on each column will be sent to code behind. There the SQL queries will be built to return the records. In such a ways, you can specify any type of SQL queries. For sorting, it is as usual SQL statement.

    If any confusion, you contact me on my mail. Also send me you detailed requirement if required any new post to my mail id.

  • venky says:
    24 April 2013 at 18:05

    Hi, When I click on the button1 (server side button) after i expand the grid I get [HttpException (0x80004005): The state information is invalid for this page and might be corrupted.]

    Any thought why this happens?

  • Thirumalai M says:
    24 April 2013 at 18:32

    Hi, I did not get any issue when clicking the button. I feel there is some other issue.Try to run the example code provided here (you download sourcecode) and test the same error comming.

    You can try to create a sample project and send me if you need me to verify. As I am not getting any issue, I could not check.

  • Anonymous says:
    16 May 2013 at 21:48

    Hi I am working to implement a similar solution to this and the only issue I am having is after the successful save of data within the child grid, the child grid does not update, I wonder if you would be so kind to tell me the modification I need to add to enable this functionality, thank you, this is great stuff.
    regards regina.

  • Thirumalai M says:
    19 May 2013 at 17:15

    Hi. Please download the source code, it will have the functionality. Normally if you have done changes using javascript (using AJAX call), you required to change the grid values manually using javascript.

    In this example, I am changing the value of the data which got changed using JavaScript only. Please verify the code.

  • Anonymous says:
    20 May 2013 at 20:21

    First thank you so much for responding, I really appreciate this quality code and that you still monitor and answer questions.
    I have downloaded the source code,and when I step through, I do see it retrieving the new information, I just never see the detail grid do an update. if I hit the edit button again, I can clearly see my change then, I just never see the update in the actual detail grid unless I restart the debugger. I am currently playing around with trying to get it to work within an update panel, not sure if that will solve it or not, Again kudos on this code, very nicely done. regards regina.

  • Thirumalai M says:
    20 May 2013 at 23:58

    Hi, Thanks for the comment. I will be happy if this implementation helps you.

    1. "I do see it retrieving the new information, I just never see the detail grid do an update." - From the JavaScript, you can have updating the child grid values from the parent grid page itself. Once it is rendered to the browser, ever javascript will be considered same. So does not matter if this not exist in detail grid.
    2. "I just never see the update in the actual detail grid unless I restart the debugger" - try to keep debugger and run the code. Verify if he code runs when updating the data.

  • Anonymous says:
    21 May 2013 at 03:27

    after the update, I get the modal dialog that the record updated successfully, and I see it run through this code again:
    $.ajax({
    url: 'ChildGridBuilder2.aspx',
    type: 'GET',
    data: "OrderID=" + encodeURIComponent(orderId),
    dataType: "html",
    success: function (response) {
    $('#div' + orderId).html(response);
    $('#div' + orderId).css("display", "block");
    $('#img' + orderId).attr('src', 'images/minus.png');
    $('#hid' + orderId).val("1");
    },
    error: function (xhr, ajaxOptions, thrownError) {
    alert('Error Occured!');
    $('#div' + orderId).css("display", "none");
    }
    });

    But this code never causes the actual child page to reload. If I put a break in the pageload it nevers hits subsequently, only the first time the child grid loads.

    if I keep running and hit the edit button again in the detail grid, it hits the get again in the handler, and the correct information is always in the edit form, I just cannot see what is stopping the childgrid from not refreshing.

  • Thirumalai M says:
    4 June 2013 at 14:23

    hi,

    The issue is because of AJAX calls are caching the data by default. Once the details are saved, the code is calling the server for getting new content using ExpandCollapse. but because the details already been retrieved from server using AJAX call, this returns the same content (without calling the server).

    To solve the issue, you can add the url with date time appended as below -
    url: 'ChildGridBuilder.aspx?datetime=' + new Date().getTime(),

    I had changed the page, you can try to change the url and try again.

  • Anonymous says:
    4 September 2013 at 03:41

    Hi,
    It would be great if u post the same implementation without the pop up window.Like the Child Grid should have the feature of editing the existing records without the pop up and also to add new records

  • Chégua says:
    8 July 2014 at 15:25

    Where is the database?

  • nani says:
    13 March 2018 at 13:08

    how to show other level grid ??? any one can help

Post a Comment