In one of my articles I discussed how to select checkboxes inside the GridView control. You can view the article here. This is an extension to that article in which, I will discuss some additional features. These features include using regular expression to limit the checkbox selection on a particular GridView and de-selecting the parent checkbox when all child checkboxes are un-checked.
Introduction:
In one of my articles I discussed how to select checkboxes inside the GridView control. You can view the article here. This is an extension to that article in which, I will discuss some additional features. These features include using regular expression to limit the checkbox selection on a particular GridView and de-selecting the parent checkbox when all child checkboxes are un-checked.
Creating the GridView Control:
The first task is to create a simple GridView control using template fields. I strongly recommend using template fields instead of bound fields for the following reasons.
1) Template fields allow embedding the ASP.NET controls.
2) You don’t have to reorganize the appearance of the GridView after a new template field is added. This is because template field do not depend on the index number like the bound fields.
3) Template fields allow access to ASP.NET controls even if the fields are not visible.
Finally, here is the code for the GridView control.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:TemplateField>
<HeaderTemplate>
<input type="checkbox" id="chkAll" name="chkAll" onclick="Check(this)" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox ID="chkSelect" runat="server" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:Label ID="lblCategoryName" runat="server" Text = '<%# Eval("CategoryName") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
The HeaderTemplate contains the HTML checkbox and serves as the parent checkbox. The ItemTemplate contains the ASP.NET checkboxes.
Populating the GridView Control:
I have used DataSet to populate the GridView control but you can use any type of container object to complete the task.
private void BindData()
{
string connectionString = "Server=localhost;Database=Northwind;Trusted_Connection=true";
SqlConnection myConnection = new SqlConnection(connectionString);
SqlDataAdapter ad = new SqlDataAdapter("SELECT CategoryID, CategoryName FROM Categories", myConnection);
DataSet ds = new DataSet();
ad.Fill(ds);
GridView1.DataSource = ds;
GridView1.DataBind();
}
Now, if you run the application you will see the GridView displayed on the page.
NOTE: I have added styles to make the GridView look pretty!
Selecting and Deselecting CheckBoxes:
At this point your GridView control is displayed on the page and we need to implement the functionality to select and deselect all the child checkboxes when the parent checkbox is checked.
If you take a look at the GridView HTML code you will notice that the parent checkbox (chkAll) fires the Check function when clicked. Let’s see the Check function implementation.
function Check(parentChk)
{
var elements = document.getElementsByTagName("INPUT");
for(i=0; i<elements.length;i++)
{
if(parentChk.checked == true)
{
if( IsCheckBox(elements[i]) && IsMatch(elements[i].id))
{
elements[i].checked = true;
}
}
else
{
elements[i].checked = false;
}
}
}
The Check function is responsible for selecting and deselecting all the child checkboxes. First, I retrieve all the objects whose tag name is “INPUT”. Inside the loop I check that if the parent checkbox is checked or not. If it is checked then I find the correct checkbox element and mark it checked. The functions IsCheckBox and IsMatch are responsible for finding the child checkboxes.
Before I explain the working of the two methods let’s see your little regular expression which separates the GridView checkboxes from other checkboxes on the page and even from the checkboxes inside other GridView controls.
Here is out little regular expression:
var pattern = '^GridView1';
The expression says that select every string whose name starts with “GridView1”. You might be thinking that how does this expression help to find the correct child checkboxes. In order to understand it let’s take a look at the HTML code that is generated when the GridView is rendered on the page.
You can see that the checkboxes inside the GridView control are assigned unique ids. The first part contains the id of the GridView which, in this case is “GridView1”. The middle part contains the row number and the final part contains the original id of the checkbox as set by the developer.
Now, let’s take a look at the IsMatch function which, takes the id of the control as a parameter and returns true if matched else returns false.
function IsMatch(id)
{
var regularExpresssion = new RegExp(pattern);
if(id.match(regularExpresssion)) return true;
else return false;
}
The IsMatch function is not enough. Huh! The reason is that we are not checking for the type of the element. The element which has the “INPUT” tag can be a checkbox, radio, textbox, button etc. For that reason there is another small method called IsCheckBox which simply checks for type of the element.
function IsCheckBox(chk)
{
if(chk.type == 'checkbox') return true;
else return false;
}
All the code that we have discussed will allow you to check and uncheck all the checkboxes based on the parent checkbox. The code also checks for the particular GridView so, that other checkboxes on the page are not affected.
Attaching Listeners to the Child CheckBoxes:
Listeners allow you to catch events generated by the controls and take action on those events by firing a function. Scott Andrew wrote an excellent piece of code that attaches the listeners to the object. The code is browser compatible (I have tested on Mozilla and IE).
function AddEvent(obj, evType, fn)
{
if (obj.addEventListener)
{
obj.addEventListener(evType, fn, true);
return true;
}
else if (obj.attachEvent)
{
var r = obj.attachEvent("on"+evType, fn);
return r;
}
else
{
return false;
}
}
I won’t be explaining the insights of this function but if you are really interested then you should check out this link.
The AddEvent function is fired from the function AttachListener.
function AttachListener()
{
var elements = document.getElementsByTagName("INPUT");
for(i=0; i< elements.length; i++)
{
if( IsCheckBox(elements[i]) && IsMatch(elements[i].id))
{
AddEvent(elements[i],'click',CheckChild);
}
}
}
In the code above I am registering the ‘click’ event of the checkboxes with a listener. Any time the click event is fired from the child checkboxes the “CheckChild” function is fired. The AttachListener is fired on the <body onload="AttachListener()"> event.
The CheckChild Function:
The CheckChild function keeps track of how many child checkboxes are checked. When all the child checkboxes are checked then the parent checkbox should also be checked.
function CheckChild(e)
{
var evt = e || window.event;
var obj = evt.target || evt.srcElement
if(obj.checked)
{
if(counter < GetChildCheckBoxCount())
{ counter++; }
}
else
{
if(counter > 0) { counter--; }
}
if(counter == GetChildCheckBoxCount())
{ document.getElementById("chkAll").checked = true; }
else if(counter < GetChildCheckBoxCount()) { document.getElementById("chkAll").checked = false; }
}
The total of checked checkboxes is stored in the global variable called “counter”. Once, the counter reaches the total child checkboxes then the parent checkbox is checked. With the global variable counter in-place there is also a small change in the Check function. Take a look at the final Check function.
function Check(parentChk)
{
var elements = document.getElementsByTagName("INPUT");
for(i=0; i<elements.length;i++)
{
if(parentChk.checked == true)
{
if( IsCheckBox(elements[i]) && IsMatch(elements[i].id))
{
elements[i].checked = true;
}
}
else
{
elements[i].checked = false;
// reset the counter
counter = 0;
}
}
if(parentChk.checked == true)
{
counter = GetChildCheckBoxCount();
}
}
Few, extra lines are added to reset the counter. The method GetChildCheckBoxCount() is pretty simple and you can view the source in the download.
Here is the small animation of the effect: