Tuesday, October 4, 2011

Check/Uncheck checkboxes in GridView using JavaScript

The question regarding how to check/uncheck CheckBoxes within a GridView control using JavaScript has been asked many times. Here is a quick reference you can follow.
First we have the .aspx markup.
<script type="text/javascript">
    function SelectAll(id) {
        var frm = document.forms[0];
        for (i=0;i<frm.elements.length;i++) {
            if (frm.elements[i].type == "checkbox") {
                frm.elements[i].checked = document.getElementById(id).checked;
            }
        }
    } 
</script>
<!-- assuming that SqlDataSource1 is the datasource for my GridView -->
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" Width="400px">
    <Columns>
        <asp:TemplateField>
            <AlternatingItemTemplate>
                <asp:CheckBox ID="CheckBox1" runat="server" />
            </AlternatingItemTemplate>
            <ItemTemplate>
                <asp:CheckBox ID="CheckBox1" runat="server" />
            </ItemTemplate>
            <HeaderTemplate>
                <asp:CheckBox ID="cbSelectAll" runat="server" Text="Select All" />
            </HeaderTemplate>
            <HeaderStyle HorizontalAlign="Left" />
            <ItemStyle HorizontalAlign="Left" />
        </asp:TemplateField>
    </Columns>
</asp:GridView>
Next we have the code-behind in both VB and C#
VB
Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
    If (e.Row.RowType = DataControlRowType.Header) Then
        'adding an attribute for onclick event on the check box in the header
        'and passing the ClientID of the Select All checkbox
        DirectCast(e.Row.FindControl("cbSelectAll"), CheckBox).Attributes.Add("onclick", "javascript:SelectAll('" & _
            DirectCast(e.Row.FindControl("cbSelectAll"), CheckBox).ClientID & "')")
    End If
End Sub
C#
protected void GridView1_RowDataBound(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e) {
    if (e.Row.RowType == DataControlRowType.Header) {
        //adding an attribute for onclick event on the check box in the header
        //and passing the ClientID of the Select All checkbox
        ((CheckBox)e.Row.FindControl("cbSelectAll")).Attributes.Add("onclick", "javascript:SelectAll('" + ((CheckBox)e.Row.FindControl("cbSelectAll")).ClientID + "')");
    }
}
The example above is fantastic, but there are a couple things that could be improved.
  1. The JavaScript Pseudo Protocol (Javascript:your method here) should be avoided, it's a fragment from the old Netscape days. Today there are better alternatives
  2. In this case we probably don't need the server-side portion altogether.
An excerpt about the JavaScript Pseudo Protocol:
"The javascript: pseudo-protocol should not be used in event handlers like onclick. It should only be used in attributes that contain a URL, for example in the href attribute of <a> elements and the action attribute of <form> elements. You can also use it to make bookmarlets." - Common JavaScript Mistakes
Another solution the .aspx markup: 
<script type="text/javascript">
    // Let's use a lowercase function name to keep with JavaScript conventions
    function selectAll(invoker) {
        // Since ASP.NET checkboxes are really HTML input elements
        //  let's get all the inputs
        var inputElements = document.getElementsByTagName('input');

        for (var i = 0 ; i < inputElements.length ; i++) {
            var myElement = inputElements[i];

            // Filter through the input types looking for checkboxes
            if (myElement.type === "checkbox") {

               // Use the invoker (our calling element) as the reference 
               //  for our checkbox status

                myElement.checked = invoker.checked;
            }
        }
    } 
</script>

<!-- assuming that SqlDataSource1 is the datasource for my GridView -->
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1">
    <Columns>
        <asp:TemplateField>
            <AlternatingItemTemplate>
                <asp:CheckBox ID="CheckBox1" runat="server" />
            </AlternatingItemTemplate>
            <ItemTemplate>
                <asp:CheckBox ID="CheckBox1" runat="server" />
            </ItemTemplate>
            <HeaderTemplate>
                <asp:CheckBox ID="cbSelectAll" runat="server" Text="Select All" OnClick="selectAll(this)" />
            </HeaderTemplate>
            <HeaderStyle HorizontalAlign="Left" />
            <ItemStyle HorizontalAlign="Left" />
        </asp:TemplateField>
    </Columns>
</asp:GridView>