Home > .NET, C# > Check all/uncheck all GridView (Client-side)

Check all/uncheck all GridView (Client-side)

Tiếp theo bài viết trước Check all/uncheck all GridView (Server-side), FB có ý nghĩ rằng: để check và uncheck các CheckBox trên web brower thì không cần thiết tới sự can thiệp của server. Những công việc xử lý giao diện không cần thao tác với database nên thực hiện ở phía client để giảm bớt những công việc lặt vặt vớ vẩn cho server. Để giải quyết việc này, FB nghĩ đến javascript (ngôn ngữ lập trình xử lý phía client), và bắt tay vào search. Và lại gặp lại Scott Mitchell với article “Checking All CheckBoxes in a GridView Using Client-Side Script and a Check All CheckBox“. FB sẽ trình bày và sắp đặt lại phương pháp mà tác giả đã đưa ra theo cách suy nghĩ của mình.

Tạo TemplateField cho GridView, thêm CheckBox HeaderLevelCheckBox vào Header và thêm CheckBox RowLevelCheckBox vào ItemTemplate. Ý tưởng là User sẽ tương tác với HeaderLevelCheckBox để check/uncheck all các RowLevelCheckBox trên các row của GridView

<asp:GridView ID="FileList" runat="server"
    AutoGenerateColumns="False" DataKeyNames="FullName">
    <Columns>
        <asp:TemplateField>
            <HeaderTemplate>
                <asp:CheckBox runat="server" ID="HeaderLevelCheckBox" />
            </HeaderTemplate>
            <ItemTemplate>
                <asp:CheckBox runat="server" ID="RowLevelCheckBox" />
            </ItemTemplate>
        </asp:TemplateField>

        <asp:BoundField DataField="Name" HeaderText="Name" />
        ... Remaining BoundFields ...
    </Columns>
</asp:GridView>

Sự kiện onclick (client-side) của HeaderLevelCheckBox sẽ gọi tới javascript function ChangeAllCheckBoxStates(checkState) với tham số checkState =  HeaderLevelCheckBox.Checked.

<script type="javascript">
function ChangeAllCheckBoxStates(checkState)
{
    // Toggles through all of the checkboxes defined in the CheckBoxIDs array
    // and updates their value to the checkState input parameter
    if (CheckBoxIDs != null)
    {
        for (var i = 0; i < CheckBoxIDs.length; i++)
           ChangeCheckBoxState(CheckBoxIDs[i], checkState);
    }
}
</script>

Đăng ký hàm cho sự kiện onclick của HeaderLevelCheckBox

Protected Sub FileList_DataBound(ByVal sender As Object,
   ByVal e As System.EventArgs) Handles FileList.DataBound
   'Each time the data is bound to the grid we need to build up the
   'CheckBoxIDs array

   'Get the header CheckBox
   Dim cbHeader As CheckBox = CType(FileList.HeaderRow.
        FindControl("HeaderLevelCheckBox"), CheckBox)

   'Run the ChangeCheckBoxState client-side function whenever the
   'header checkbox is checked/unchecked
   cbHeader.Attributes("onclick") = "ChangeAllCheckBoxStates(this.checked);"

   For Each gvr As GridViewRow In FileList.Rows
     'Get a programmatic reference to the CheckBox control
     Dim cb As CheckBox = CType(gvr.FindControl("RowLevelCheckBox"), CheckBox)

     'Add the CheckBox's ID to the client-side CheckBoxIDs array
     ClientScript.RegisterArrayDeclaration("CheckBoxIDs",
              String.Concat("'", cb.ClientID, "'"))
   Next
End Sub

CheckBoxIDs là biến của javascript lưu trữ  danh sách ClientID của các CheckBox trong GridView. CheckBoxIDs sẽ được hàm ChangeAllCheckBoxStates sử dụng để thu được các checkbox control trên web brower.

Như vậy, chúng ta đã có 1 gridview mà khi header checkbox được check/uncheck thì các row checkbox cũng được check/uncheck theo.

Vấn đề 1: Khi user tự check toàn bộ các row checkbox hoặc uncheck 1 row thì CheckState của header checkbox không được cập nhật

Để giải quyết vấn đề này, ta sẽ đăng ký sự kiện onclick của mỗi row checkbox tới 1 hàm javascritp ChangeHeaderAsNeed(). Hàm này sẽ kiểm tra nếu tất cả các row checkbox có checkstate = true thì sẽ thay đổi checkstate của header checkbox = true, còn không thì checkstate của header checkbox = false.

function ChangeHeaderAsNeeded()
{
    // Whenever a checkbox in the GridView is toggled, we need to
    // check the Header checkbox if ALL of the GridView checkboxes are
    // checked, and uncheck it otherwise
    if (CheckBoxIDs != null)
    {
        // check to see if all other checkboxes are checked
        for (var i = 1; i < CheckBoxIDs.length; i++)
        {
            var cb = document.getElementById(CheckBoxIDs[i]);
            if (!cb.checked)
            {
                // Whoops, there is an unchecked checkbox, make sure
                // that the header checkbox is unchecked
                ChangeCheckBoxState(CheckBoxIDs[0], false);
                return;
            }
        }

        // If we reach here, ALL GridView checkboxes are checked
        ChangeCheckBoxState(CheckBoxIDs[0], true);
    }
}

Tại hàm FileList_DataBound thêm đoạn sau:

... Code omitted for brevity ...
For Each gvr As GridViewRow In FileList.Rows
    'Get a programmatic reference to the CheckBox control
    Dim cb As CheckBox = CType(gvr.FindControl("RowLevelCheckBox"), CheckBox)

   'If the checkbox is unchecked, ensure that the Header CheckBox is unchecked
   cb.Attributes("onclick") = "ChangeHeaderAsNeeded();"

    'Add the CheckBox's ID to the client-side CheckBoxIDs array
    ClientScript.RegisterArrayDeclaration("CheckBoxIDs", 
        String.Concat("'", cb.ClientID, "'"))
Next

Vấn đề 2:  Khi trang được postback mà không phải bind data lại cho gridview, checkstate của các row checkbox không được cập nhật khi check/uncheck row header

Vấn đề này phát sinh là do sau khi trang postback (ko cần rebind. ví dụ ấn vào 1 nút nào đó trên trang) thì sự kiện DataBound của gridview không xảy ra, do đó biến CheckBoxIDs (client-side) không được khai báo (biến này không được lưu vào ViewState vì nó được khai báo bởi ClientScript), dẫn tới các hàm javascript sử dụng biến này đều không thực thi được.

Để giải quyết, ta sử dụng Literal Web control. Ta sẽ sử  dụng thuốc tính Text của Literal để khai báo biến CheckBoxIDs (thuộc tính này được lưu trữ trong ViewState, nên khi postback nó vẫn còn giá trị)

Protected Sub FileList_DataBound(ByVal sender As Object, ByVal e As System.EventArgs) Handles FileList.DataBound
 ... Code omitted for brevity ...

 'Add the CheckBox's ID to the client-side CheckBoxIDs array
 Dim ArrayValues As New List(Of String)
 ArrayValues.Add(String.Concat("'", cbHeader.ClientID, "'"))

 For Each gvr As GridViewRow In FileList.Rows
 'Get a programmatic reference to the CheckBox control
 Dim cb As CheckBox = CType(gvr.FindControl("RowLevelCheckBox"), CheckBox)

 'If the checkbox is unchecked, ensure that the Header CheckBox is unchecked
 cb.Attributes("onclick") = "ChangeHeaderAsNeeded();"

 'Add the CheckBox's ID to the client-side CheckBoxIDs array
 ArrayValues.Add(String.Concat("'", cb.ClientID, "'"))
 Next

 'Output the array to the Literal control (CheckBoxIDsArray)
 CheckBoxIDsArray.Text = "<script type=""text/javascript"">" & vbCrLf & _
 "<!--" & vbCrLf & _
 String.Concat("var CheckBoxIDs = new Array(", 
     String.Join(",", ArrayValues.ToArray()), ");") & vbCrLf & _
        "// -->" & vbCrLf & _
        "</script>"
End Sub

Như vậy, ta đã có được một gridview với các checkbox làm việc một cách logic. Hy vọng nó sẽ giúp ích cho các bạn trong quá trình làm việc!

Categories: .NET, C# Tags: , ,
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: