Monday, December 21, 2009

Retrieving controls from an ASP.NET GridView control using javascript.

In our day to day ASP.NET programming we would have used GridView for one or the other purpose. There would have been requirement to access the controls inside a GridView from javascript. Whenever I had to use the ASP.NET GridView control, nearly 95% of the time I had to access the controls inside the GridView using javascript for one or the other purpose. With this blog I wanted to show how easily you can retrieve controls rendered inside a GridView from javascript. I would like to highlight this by taking an age old design where you will have a checkbox in the header and another set of checkboxes in the column below. Checking the checkbox in the header would select all the checkboxes in the column and un-checking a single checkbox in the column would un-check the header checkbox. This strategy can be used to access any type of controls not only inside the GridView but other data rendering controls as well. Now lets see the code for the same.

<asp:GridView ID="gvChk" runat="server" AutoGenerateColumns="False"
            BackColor="White" BorderColor="#DEDFDE" BorderStyle="None" BorderWidth="1px"
            CellPadding="4" ForeColor="Black" GridLines="Vertical"
            onrowdatabound="gvChk_RowDataBound">
            <RowStyle BackColor="#F7F7DE" />
            <Columns>
                <asp:TemplateField HeaderText="Sl. No">
                    <EditItemTemplate>
                        <asp:TextBox ID="TextBox1" Text='<%#Eval("No") %>' runat="server"></asp:TextBox>
                    </EditItemTemplate>
                    <ItemTemplate>
                        <asp:Label ID="Label1" runat="server" Text='<%#Eval("No") %>'></asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField>
                    <EditItemTemplate>
                        <asp:CheckBox ID="CheckBox1" runat="server" />
                    </EditItemTemplate>
                    <ItemTemplate>
                        <asp:CheckBox ID="CheckBox1" runat="server" />
                    </ItemTemplate>
                    <HeaderTemplate>
                        <asp:CheckBox ID="chkHeader" onclick="javascript:selectAllCheckboxInGrid(<% gvChk.ClientID; %>, this);"
                            runat="server" />
                    </HeaderTemplate>
                </asp:TemplateField>
            </Columns>
            <FooterStyle BackColor="#CCCC99" />
            <PagerStyle BackColor="#F7F7DE" ForeColor="Black" HorizontalAlign="Right" />
            <SelectedRowStyle BackColor="#CE5D5A" Font-Bold="True" ForeColor="White" />
            <HeaderStyle BackColor="#6B696B" Font-Bold="True" ForeColor="White" />
            <AlternatingRowStyle BackColor="White" />
</asp:GridView>

The code is very simple with a GridView control having two columns. First column has a label control and second one has a checkbox control. The second column has a checkbox in the header as well. When checkbox in the header is clicked all the checkboxes in the column are selected using javascript. The javascript code to select all the checkboxes in the column are pasted below.

function selectAllCheckboxInGrid(gridID, chk)
{
    var grid = document.getElementById(gridID);
    //Loop starts from 1 because the zeroth row is the header.
    for (var i=1; i< grid.rows.length; i++)
    {
        //Getting the control in the second cell of the grid.
        //Second cell contains the checkbox.
        var cntls = grid.rows[i].cells[1].getElementsByTagName('input');
        //If you are have only one control in the cell then
        //one can do away with the loop.
        for (var j=0; j < cntls.length; j++)
        {
            if (cntls[j].type == "checkbox")
                cntls[j].checked = chk.checked;
        }
    }   
}

The above pasted javascript is straight forward. The javascript function takes two arguments, one is the GridView’ client id and the second is the checkbox in the GridView control’ header. The function starts by getting the grid control using the “getElementById” javascript method of the document object. After getting the GridView control, which is converted to a HTML table once rendered to the browser, we are looping through the rows collection starting from the first row. The zeroth row is the header so we don’t want the loop to start from the header. Starting from the 1st row we loop through the whole rows and get the controls in the second cell of the GridView using the “getElementsByTagName” method of the document object. Then we loop through the control array and check the type of the control and if it is a checkbox we set the checked property based on the checkbox control of the header cell passed as an argument to the javascript function. If you have only one control in the cell then you can directly use “cells[1].children[0].checked = chk.checked” so that you can avoid the loop. The above modified code is pasted below.

function selectAllCheckboxInGrid(gridID, chk)
{
    var grid = document.getElementById(gridID);
    //Loop starts from 1 because the zeroth row is the header.
    for (var i=1; i< grid.rows.length; i++)
    {
        //Getting the control in the second cell of the grid.
        //Second cell contains the checkbox.
        var cntls = grid.rows[i].cells[1].children[0].checked = chk.checked
    }   
}

Next we have to have a function which will check the header checkbox if all the checkbox in the column are checked and if out of all the checked checkboxes anyone is unchecked then we need to uncheck the header checkbox. The simple function is fired when any of the checkboxes in the column are clicked. The javascript function is pasted below.

function checkUncheckHeaderCheckBox(gridID)
{
    var grid = document.getElementById(gridID);
    var checked = true;
    //Loop starts from 1 because the zeroth row is the header.
    for (var i=1; i< grid.rows.length; i++)
    {
        //Getting the control in the second cell of the grid.
        //Second cell contains the checkbox.
        var cntls = grid.rows[i].cells[1].getElementsByTagName('input');
        //If you are have only one control in the cell then
        //one can do away with the loop.
        for (var j=0; j < cntls.length; j++)
        {
            if (cntls[j].type == "checkbox" && !cntls[j].checked)
            {
                checked = cntls[j].checked;
                break;
            }
        }
        if (!checked)
            break;
    }   
    //Get the header checkbox and assign its checked property.
    grid.rows[0].cells[1].children[0].checked = checked;   
}

The above function is pretty straight forward. The “GridView” control id is passed as argument. The function gets the “GridView” control using the “getElementById” function of the document object and loops through the rows starting from the first row leaving the zeroth row. Inside the loop the function retrieves the controls inside the second cell of each row and checks whether any one of the checkbox is unchecked. If so it assigns the “checked” variable as false and breaks the loop. Finally it sets the checked property of the checkbox in the header (zeroth row) to the value of “checked” variable. This function will take care of checking or unchecking the checkbox if all the checkbox in the column are checked or if any one checkbox in the checkbox column is unchecked respectively.

To fire the javascript function on the click of the checkboxes we need to add the javascript function to the “onclick” javascript event. To do this add the following in the “RowDataBound” event of the GridView control.

protected void gvChk_RowDataBound(object sender, GridViewRowEventArgs e)
{
    //Check if the row is of header type.
    if (e.Row.RowType == DataControlRowType.Header)
    {
        //Add the javascript function which gets called
        //when the checkbox in the header is clicked.
        (e.Row.FindControl("chkHeader") as CheckBox).Attributes.Add("onclick", "javascript:selectAllCheckboxInGrid('" + gvChk.ClientID + "', this);");
    }
    else if (e.Row.RowType != DataControlRowType.Footer)
    {
        //Add the javascript function call which gets called
        //when the checkboxes in the column are clicked.
        (e.Row.FindControl("CheckBox1") as CheckBox).Attributes.Add("onclick", "javascript:checkUncheckHeaderCheckBox('" + gvChk.ClientID + "');");
    }
}

With the above code we are ready to go.

The above technique using javascript can be used to retrieve any type of controls (textbox, dropdown, radio button, button, links, images, labels etc) from within the GridView control or any other ASP.NET data rendering controls. You need to make some small javascript changes according to your data bound controls layout. So tweak the code wherever necessary and start retrieving controls.

Try to know more…

Sandeep

1 comment:

Please provide your valuable comments.