Make "Check All" to include only displayed list options in Excel-like filtering

5 posts, 0 answers
  1. Attila Antal
    Admin
    Attila Antal avatar
    384 posts

    Posted 27 Dec 2017 Link to this post

    Requirements

    Telerik Product and Version

    3.5+

    Supported Browsers and Platforms

    All browsers supported by Telerik UI for ASP .NET AJAX

    Components/Widgets used (JS frameworks, etc.)

    JavaScript

    PROJECT DESCRIPTION 

    Clicking on "Check All" checkbox will check only displayed items when CheckList Filtering is enabled.



     

    C# - In the code behind, using the PreRender event of the Page, bind two event handlers to RadListBox holding the checkbox items.

    protected void Page_PreRender(object sender, EventArgs e)
    {
        var lb = RadGrid1.FindControl("filterCheckList") as RadListBox;
        lb.OnClientLoad = "listBoxLoad";
        lb.OnClientCheckAllChecked = "CheckAllChecked";
    }

     

      UPDATED  

    In order to improve performance of this functionality, we have overridden few internal functions, so to use jQuery to do the job instead of accessing and iterating through Object classes.

    With this change, now selection works almost instantly with even 2-3 thousand records. An Updated version of the project is attached.

     

    JavaScript - Client side code to manipulate the checklist items.

    <script type="text/javascript">
        function listBoxLoad(sender, args) {
            // reference to the ListBox
            var listBoxElement = $telerik.$(sender.get_element());
            //listBoxElement.find('input[id$="filterCheckListSearch"]').on('keyup', function () {
            //    debugger;
            //});
            // reference to the List Group
            var listBoxGroup = listBoxElement.find('.rlbGroup');
            // create a custom Check All Checkbox and add it to the list group
            listBoxGroup.prepend('<div class="myChekAllCheckBox" style="display: none;"><label><input type="checkbox" class="customCheckAll">Check All</label></div>');
    
            // wire up the change event to the Custom Check All Checkbox.
            // when changed, execute the script inside the function
            listBoxGroup.find('.customCheckAll').change(function (e) {
                // find only the visible listbox items (li)
                var lbItems = listBoxGroup.find('.rlbList li:visible');
                // find the checkboxes within the visible listbox items and check/uncheck them based on the Check All Checkbox state
                lbItems.find('input').prop('checked', this.checked);
    
                if (this.checked) {
                    // uncheck other items
                    listBoxGroup.find('.rlbList li:hidden input').prop('checked', false);
                }
            });
    
            // attach the following two events - For the Show Loading indicator functionality
            sender.add_itemsRequested(hideLbLoadingSign);
            sender.add_itemsRequestFailed(hideLbLoadingSign);
        }
    
        function hideLbLoadingSign(sender, args) {
            //remove the custom loading sign class
            $telerik.$(sender.get_element()).find(".rlbGroup").first().removeClass("lbLoadingSign");
            // show the check all checkbox
            $telerik.$(sender.get_element()).find(".rlbGroup .myChekAllCheckBox").first().show();
        }
    
        function showLoadingSign(sender, args) {
            //add the custom loading sign class
            $telerik.$(sender.get_childListElement()).find(".rlbGroup").first().addClass("lbLoadingSign");
        }
    
        function OnClientHidden(sender, args) {
            // Optional: hide the Check All checkbox when the menu closed
    
            // selector to select all occurences of .RadMenu.myCheckAllCheckBox on the page
            $telerik.$(".RadMenu .rgHCMFilter .RadListBox .myChekAllCheckBox").hide();
    
            // get reference to RadGrid this ContextMenu belongs.
            var currentRadGrid = sender.get_parent();
    
            // selector to select only the myCheckAllCheckBox that belongs to the current RadGrid firing opening this ContextMenu.
            $telerik.$(".RadMenu[id^='" + currentRadGrid.ClientID + "'] .rgHCMFilter .RadListBox .myChekAllCheckBox").hide();
        }
        // handle filtering
        Telerik.Web.UI.Grid.FilterSearch = function (grid, input) {
            var ListBox = $telerik.$('#' + grid._filterCheckListClientID)
            // hide all as soon as start searching
            ListBox.find('.rlbList li').hide();
            // show only search results
            var visibleItems = ListBox.find('.rlbList li:contains(' + input.value.toLowerCase() + ')').show();
    
            var visibleItemsCount = visibleItems.length;
            var checkedItemsCount = visibleItems.find('input[type="checkbox"]:checked').length;
            // Check/Uncheck the CheckAll checkbox whether all visible items on the list are checked
            ListBox.find('.myChekAllCheckBox input[type="checkbox"]').prop('checked', visibleItemsCount > 0 && visibleItemsCount == checkedItemsCount);
        }
        // handle per item check
        Telerik.Web.UI.RadListBox.prototype._onCheck = function (e, targetItem) {
            var ListBox = $telerik.$(e.target).closest('.RadListBox');
    
            var visibleItems = ListBox.find('.rlbList li:visible');
    
            var visibleItemsCount = visibleItems.length;
            var checkedItemsCount = visibleItems.find('input[type="checkbox"]:checked').length;
    
            // Check/Uncheck the CheckAll checkbox whether all visible items on the list are checked
            ListBox.find('.myChekAllCheckBox input[type="checkbox"]').prop('checked', visibleItemsCount > 0 && visibleItemsCount == checkedItemsCount);
        }
    </script>

     

    Note: This sample project is a custom solution that is beyond the RadGrid's built-in functionality. This was intended to be a demonstration for customizing the RadGrid control. Further customization or improvement of this example will not be guaranteed.

  2. merikmgrasp
    merikmgrasp avatar
    4 posts
    Member since:
    May 2007

    Posted 30 Mar 2018 in reply to Attila Antal Link to this post

    Thanks for this answer.  It does in fact work but unfortunately in our case, it is way too slow to be usable.

    Our databases are quite large and thus the filter list is large too.  In my example I have 1300 items in the filter checkbox list.

    In the provided sample method:

                function CheckAllChecked(sender, args) {
                    var items = sender.get_items();
                    for (var i = 0; i < items.get_count() ; i++) {
                        var item = items.getItem(i);
                        item.set_checked(!checkedState && item.get_visible());
                    }
                    sender.get_checkAllCheckBox().checked = !checkedState;
                }

    The item.set_checked() method called 1300 times in the for loop is taking between 30 and 40 seconds which makes it impracticable for clients to use.

    In the loop I tried bypassing the set_checked() method and instead getting the checkbox element and setting its checked property instead.  The loop then took less than a second to run, but when the grid's NeedDataSource method is called, the grid's filter expression (myGrid.MasterTableView.FilterExpression) is blank.

    I tried another workaround where in the loop I stored the checked item values in a string which I then store into session in an ajax call.  Then in the NeedDataSource method I built the filter expression for those checked items manually.  The problem then was that I needed to store the checked items for each column as multiple columns can be filtered at the same time.  Then there was also a problem with view state and the checked items.

    For now, I have just hidden the "Check All" checkbox in the filter dropdown using the CSS style:

            .rlbCheckAllItems { display: none; }

    If you have any other suggestions as to how to speed up that item.set_checked() method I'd love to hear them. Otherwise I will continue to simply hide the Check All option for now.

    Thanks

    Courtney

     

     

  3. Attila Antal
    Admin
    Attila Antal avatar
    384 posts

    Posted 07 Oct Link to this post

    Hi Courtney,

    Since this improvement has been requested by multiple developer, I've took some time and made few changes to the sample. Content and attachment have been updated accordingly.

    Please note that the sample project is custom and did not go under intensive testing and therefore we cannot guarantee its proper functioning in all scenarios.

    Kind regards,
    Attila Antal
    Progress Telerik

    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  4. Larry
    Larry avatar
    1 posts
    Member since:
    Aug 2016

    Posted 10 Oct in reply to Attila Antal Link to this post

    Please help me out so I can implement your code. Your code has one, perhaps two, hard-coded names that don't allow me to use it. 

    First, the JS has the name "RadGrid1" hard-coded in the method :

                function OnClientHidden(sender, args) { ...}

    I need to implement this is about a dozen different grids; each with its own name. Can you change this code to derive the name of the grid from the input arguments (sender, args)?

     

    Second, your example doesn't explicitly declare the checkboxes; I assume you are using some sort of default names. However, my code explicitly declares them as the following template. Please tell me what changes need to made to the JS code in this scenario.

    <Columns>
    <telerik:GridTemplateColumn   AllowFiltering="false" EnableHeaderContextMenu="false" HeaderStyle-Width="40px" ItemStyle-Width="40px" UniqueName="CheckBoxTemplateColumn">
    <ItemTemplate>
    <asp:CheckBox ID="CheckBoxProduct" runat="server"  />
    </ItemTemplate>
    <HeaderTemplate>
    <asp:CheckBox ID="CheckBoxAllProducts"  runat="server"   />
    </HeaderTemplate>
    </telerik:GridTemplateColumn>

    Thanks

    Larry

     

  5. Attila Antal
    Admin
    Attila Antal avatar
    384 posts

    Posted 10 Oct Link to this post

    Hi Larry,

    I've changed the code to target the current grid instead of having a hard-coded name.

Back to Top