Introduction
Here, I am going to present how to maintain selected CheckBox
es’ states in different pages inside the GridView
control.
Background
If you have a Gmail account then probably you have observed a great feature of maintaining selected CheckBoxes
states in different pages on Inbox Grid, i.e. suppose that you are in the first page of your Inbox & select some mails through CheckBoxes & move to the second page. You also select some mails there and further move to the next page. Finally you return back to the first/second page where you find that all the previously selected mails are already selected. This means that Gmail maintains all the selected mails’ states in deferent pages of Inbox Grid. Now if you select mails in different pages of the Inbox Grid & click Delete link, then only current page’s selected mails are deleted. But my clients wanted some more advanced features. Actually my client’s requirement was to delete all pages’ selected mails by clicking on Delete link. So I started to work on it & finally came up with this solution.
Implementation Details
To implement this functionality, I've divided it into three parts:
- Selecting / Deselecting all the
CheckBoxes
Inside a GridView
.
I've achieved this functionality using HeaderClick
& ChildClick
JavaScript methods. - Restoring selected
CheckBoxes
states Inside a GridView
for particular pages.
I've achieved this functionality by invoking RestoreState
method in the window.onload event
. - Storing selected
Checkboxes
Row-Ids.
I've used HiddenField hdnFldSelectedValues
for this purpose. It maintains Row-Ids of selected CheckBoxes’
separated by ‘|’.
HTML Code
I have used a TemplateField
inside the GridView
& put a CheckBox
and a HiddenField
in the ItemTemplate
as well as another CheckBox
in the HeaderTemplate
of the TemplateField
. To identify each GridView Row
uniquely, I've used AutoIncrement
column in the datasource & bind it to the HiddenField hdnFldId
. But it can be anything, e.g. row id from the database, etc.
<asp:GridView ID="gvCheckboxes" runat="server"
AutoGenerateColumns="False" AllowPaging="True"
OnPageIndexChanging="gvCheckboxes_PageIndexChanging"
OnRowDataBound="gvCheckboxes_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="Select">
<ItemTemplate>
<asp:CheckBox ID="chkBxSelect" runat="server" />
<asp:HiddenField ID="hdnFldId" runat="server" Value='<%# Eval("Id") %>' />
</ItemTemplate>
<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="50px" />
<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="50px" />
<HeaderTemplate>
<asp:CheckBox ID="chkBxHeader" onclick="javascript:HeaderClick(this);"
runat="server" />
</HeaderTemplate>
</asp:TemplateField>
<asp:BoundField DataField="RandomNo" HeaderText="Random Number">
<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="150px" />
<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="150px" />
</asp:BoundField>
<asp:BoundField DataField="Date" HeaderText="Date">
<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="75px" />
<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="75px" />
</asp:BoundField>
<asp:BoundField DataField="Time" HeaderText="Time">
<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="100px" />
<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="100px" />
</asp:BoundField>
</Columns>
<RowStyle BackColor="Moccasin" />
<AlternatingRowStyle BackColor="NavajoWhite" />
<HeaderStyle BackColor="DarkOrange" Font-Bold="True" ForeColor="White" />
</asp:GridView>
I've also added a HiddenFiled
in the page to keep track of Row-Ids of corresponding selected CheckBoxes
.
<asp:HiddenField ID="hdnFldSelectedValues" runat="server" />
Attaching Click Events
I've attached onclick event
on header CheckBox
as:
<asp:CheckBox ID="chkBxHeader"
onclick="javascript:HeaderClick(this);" runat="server" />
I've also attached onclick event
on each Row-CheckBox
through RowDataBound event
of the GridView
as:
if (e.Row.RowType == DataControlRowType.DataRow &&
(e.Row.RowState == DataControlRowState.Normal ||
e.Row.RowState == DataControlRowState.Alternate))
{
CheckBox chkBxSelect = (CheckBox)e.Row.Cells[0].FindControl("chkBxSelect");
CheckBox chkBxHeader = (CheckBox)this.gvCheckboxes.HeaderRow.FindControl
("chkBxHeader");
HiddenField hdnFldId = (HiddenField)e.Row.Cells[0].FindControl("hdnFldId");
chkBxSelect.Attributes["onclick"] = string.Format
(
"javascript:ChildClick(this,document.
getElementById('{0}'),'{1}');",
chkBxHeader.ClientID, hdnFldId.Value.Trim()
);
}
Page’s window.onload Event
I've used window.onload event
to initialize global variables as well as to restore the previous states of all CheckBoxes
in a particular column inside the GridView
.
var TargetBaseControl = null;
var CheckBoxes;
var CheckedCheckBoxes;
var SelectedItems;
var SelectedValues;
window.onload = function()
{
try
{
TargetBaseControl = document.getElementById('<%= this.gvCheckboxes.ClientID %>');
}
catch(err)
{
TargetBaseControl = null;
}
try
{
CheckBoxes = parseInt('<%= this.gvCheckboxes.Rows.Count %>');
}
catch(err)
{
CheckBoxes = 0;
}
CheckedCheckBoxes = 0;
SelectedValues = document.getElementById('<%= this.hdnFldSelectedValues.ClientID %>');
if(SelectedValues.value == '')
SelectedItems = new Array();
else
SelectedItems = SelectedValues.value.split('|');
if(TargetBaseControl != null)
RestoreState();
}
GridView’s Header Checkbox’s Click Event
This event
gets fired whenever GridView’s
header CheckBox
is clicked. In this event
, states of all Row-CheckBoxes
is changed depending upon the state of the header CheckBox
as well as Id of each Row is maintained in the SelectedItems array
if header CheckBox
is checked, else removed from the SelectedItems array
. Values of SelectedValues <code><code>H
iddenField & CheckedCheckBoxes
counter are also updated in this event
.
function HeaderClick(CheckBox)
{
var Inputs = TargetBaseControl.getElementsByTagName('input');
for(var n = 0; n < Inputs.length; ++n)
if(Inputs[n].type == 'checkbox' && Inputs[n].id.indexOf('chkBxSelect',0) >= 0)
{
Inputs[n].checked = CheckBox.checked;
if(CheckBox.checked)
SelectedItems.push(document.getElementById(Inputs[n].id.replace
('chkBxSelect','hdnFldId')).value);
else
DeleteItem(document.getElementById(Inputs[n].id.replace
('chkBxSelect','hdnFldId')).value);
}
SelectedValues.value = SelectedItems.join('|');
CheckedCheckBoxes = CheckBox.checked ? CheckBoxes : 0;
}
GridView’s Rows Checkboxes’s Click Event
This event
gets fired whenever any CheckBox
of GridView’s
Rows CheckBoxes
is clicked. In this event
, first CheckedCheckBoxes
counter is updated & state of the header CheckBox
is changed accordingly. After that entry for Row-Id
containing this particular ChecBox
is maintained/removed in/from the SelectedItems array
. Then value of SelectedValues HiddenField
is updated from the SelectedItems array
.
function ChildClick(CheckBox, HCheckBox, Id)
{
if(CheckBox.checked && CheckedCheckBoxes < CheckBoxes)
CheckedCheckBoxes++;
else if(CheckedCheckBoxes > 0)
CheckedCheckBoxes--;
if(CheckedCheckBoxes < CheckBoxes)
HCheckBox.checked = false;
else if(CheckedCheckBoxes == CheckBoxes)
HCheckBox.checked = true;
if(CheckBox.checked)
SelectedItems.push(Id);
else
DeleteItem(Id);
SelectedValues.value = SelectedItems.join('|');
}
RestoreState Method
This method is invoked in the window.onload event
. This method is basically used to restore the previous states of all CheckBoxes
in a particular column inside the GridView
in deferent pages. If the entry of a particular CheckBox
is found in the SelectedItems array
, then its state becomes checked. After that state of the header CheckBox
is also updated.
function RestoreState()
{
var Inputs = TargetBaseControl.getElementsByTagName('input');
var HCheckBox = null;
for(var n = 0; n < Inputs.length; ++n)
if(Inputs[n].type == 'checkbox' && Inputs[n].id.indexOf('chkBxSelect',0) >= 0)
if(IsItemExists(document.getElementById(Inputs[n].id.replace
('chkBxSelect','hdnFldId')).value) > -1)
{
Inputs[n].checked = true;
CheckedCheckBoxes++;
}
else
Inputs[n].checked = false;
else if(Inputs[n].type == 'checkbox' &&
Inputs[n].id.indexOf('chkBxHeader',0) >= 0)
HCheckBox = Inputs[n];
if(CheckedCheckBoxes < CheckBoxes)
HCheckBox.checked = false;
else if(CheckedCheckBoxes == CheckBoxes)
HCheckBox.checked = true;
}
DeleteItem Method
This method is used to remove an entry for a particular CheckBox
from the SelectedItems array
.
function DeleteItem(Text)
{
var n = IsItemExists(Text);
if( n > -1)
SelectedItems.splice(n,1);
}
IsItemExists Method
This method is used to check whether an entry for a particular CheckBox
exists in the SelectedItems array
or not.
function IsItemExists(Text)
{
for(var n = 0; n < SelectedItems.length; ++n)
if(SelectedItems[n] == Text)
return n;
return -1;
}
Deleting Selected Items From Different Pages
Now finally to delete all selected CheckBoxes
in all different pages. Simply get all the selected Ids & delete selected items using appropriate method in the Link's
/Button's
delete event
handler as:
protected void btnDelete_Click(object sender, EventArgs e)
{
string[] IDs = hdnFldSelectedValues.Value.Trim().Split('|');
foreach (string Item in IDs)
{
}
}
Conclusion
So this is my solution. If you have some other ideas about this functionality, please share them with me.
Supporting Browsers
I have tested this functionality using the following browsers:
History
- 18th December, 2008 -- Original version posted
- 26th December, 2008 -- Article updated