Friday, December 30, 2005

"SelectAll" CheckBox for DataGrid Web Control in ASP.NET

Goal: Assuming you have already added a checkbox column to
the DataGrid web control using TemplateColumn. Now you want to add a
checkbox in the header of this column to select/clear all the
checkboxes in the column.

Solution: besides adding the select all check box to the
DataGrid, you will only need 3 JavaScript functions and 2 lines of
code to accomplish this.

1. Add a CheckBox to the HeaderTemplate of the checkbox column.
Set the name to:

the name of ItemTemplate + "SelectAll";

2. In the code-behind, "Page_Load" function add this:

string scriptString = "<script language='javascript'>\n" +
"<!-- Hide script from old browsers.\n" +
"bindSelectAllCheckBox(" +
"'CheckBoxCol'" + //unfortunately, this is a hard-coded name of checkbox
",'" +
[YourDataGrid].ClientID + //replace with the name of your datagrid
"')" + "\n"+
"// End of hiding here. -->\n" +
"</script>";
RegisterStartupScript("CBSelectAll", scriptString);

3. The Javascript:

var gSelectAllTable; //global class to save information
function SelectAllCB_Click()
{
var bChecked = gSelectAllTable.SelectAllCB.checked;
var numCBs = gSelectAllTable.CheckBoxes.length
for(var i = 0; i < numCBs; i++)
{
gSelectAllTable.CheckBoxes[i].checked = bChecked;
}
gSelectAllTable.NumChecked = (bChecked) ? numCBs : 0;
}

function CheckBox_Click()
{
gSelectAllTable.NumChecked += this.checked ? 1 : -1;
gSelectAllTable.SelectAllCB.checked =
(gSelectAllTable.NumChecked == gSelectAllTable.CheckBoxes.length) ? true : false;
}

function bindSelectAllCheckBox(cbASPID, tableID)
//Assumptions:
// 1. only one such select check box is implemented on a page
// 2. the SelectAll check box's ID is composed "SelectAll"
//Parameters:
// cbASPID: ID (not ClientID) of the checkboxes
// tableID: ClientID of the table whose checkboxes will be selected
{
//regular expression for checkbox
var re = new RegExp(':' + cbASPID + '$');
//regex for select all
var reall = new RegExp(':' + cbASPID + 'SelectAll$');
gSelectAllTable = document.getElementById(tableID);
gSelectAllTable.CheckBoxes = new Array();
gSelectAllTable.NumChecked = 0;
var cbCount = 0;

if(gSelectAllTable)
{
var fm = document.forms[0];
for(var i = 0; i < fm.elements.length; i++)
{
elm = fm.elements[i];
if(elm.type == 'checkbox')
{
if(reall.test(elm.name))
{ //select all check box
gSelectAllTable.SelectAllCB = elm;
elm.onclick = SelectAllCB_Click;
}
else if(re.test(elm.name))
{ //other check boxes
gSelectAllTable.CheckBoxes[cbCount] = elm;
cbCount++;
if(elm.checked)
{
gSelectAllTable.NumChecked++;
}
elm.onclick = CheckBox_Click;
}
}
}

}
}


What can be improved:

  1. The ID of CheckBox is hardcoded.We cannot catch any typo in compile time.

  2. This implementation cannot handle 2 or more such DataGrid on one page;

  3. This implementation cannot handle CheckBox in "EditItemTemplate";

This implementation is inspired by:

  1. DHTML Utopia: Modern Web Design Using JavaScript & DOM:
    http://www.sitepoint.com/books/dhtml1/?SID=878198150071901bb10971055cb72d00

  2. Yahoo Email: http://mail.yahoo.com


Print pages from [X] to [Y] in Adobe Reader

Ever feel frustrated when you are trying to print chapters of an e-book in Adobe Reader? Let's assume you want to start at page 1 of the book which is actually page 23 in the file (because there are 22 pages of book cover and table on contents before it). If you type 23 in the from box, you may get the real page 23 which is 22 pages after the page you want to print. So, you change that number to 1, guess what, you get the book cover.

If you don't know what I am talking about, don't try to understand the paragraph above. The tips below are still useful. They will give you more confidence in knowing what pages are sent to the printer:

1. In Edit->Preferences, select "Page Display", and uncheck "Use logical page numbers";
2. Enclose the page number with "(" and ")" to get absolute page numbering;