Update slick.checkboxselectcolumn.js

When working with Row Grouping the "header checkbox" is never selected, for that reason we need to change line 54.

It is never selected because you are comparing selectedRows.lenght with _grid.getDataLength() which returns the values of the rendered rows and not the value of the dataView.Items.

The exmple code to test that is as fallow:

<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html>
    <head>
        <title>SlickGrid example: Grouping</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta name="viewport" content="width=device-width">

        <link rel="stylesheet" href="SlickGrid/examples/examples.css" type="text/css"/>

        <link rel="stylesheet" href="SlickGrid/slick.grid.css" type="text/css"/>
        <link rel="stylesheet" href="SlickGrid/controls/slick.pager.css" type="text/css"/>
        <link rel="stylesheet" href="SlickGrid/css/smoothness/jquery-ui-1.8.16.custom.css" type="text/css"/>
        <link rel="stylesheet" href="SlickGrid/controls/slick.columnpicker.css" type="text/css"/>
        <style>
            .cell-effort-driven {
                text-align: center;
            }

            .slick-group-title[level='0'] {
                font-weight: bold;
            }

            .slick-group-title[level='1'] {
                text-decoration: underline;
            }

            .slick-group-title[level='2'] {
                font-style: italic;
            }
            .slick-cell-checkboxsel {
                background: #f0f0f0;
                border-right-color: silver;
                border-right-style: solid;
            }
        </style>
    </head>
    <body>
        <div id="myGrid" style="width:700px;height:500px;"></div>


        <script src="SlickGrid/lib/jquery-1.7.min.js"></script>
        <script src="SlickGrid/lib/jquery-ui-1.8.16.custom.min.js"></script>
        <script src="SlickGrid/lib/jquery.event.drag-2.2.js"></script>

        <script src="SlickGrid/slick.core.js"></script>
        <script src="SlickGrid/slick.formatters.js"></script>
        <script src="SlickGrid/slick.editors.js"></script>
        <script src="SlickGrid/plugins/slick.checkboxselectcolumn.js"></script>
        <script src="SlickGrid/plugins/slick.rowselectionmodel.js"></script>
        <script src="SlickGrid/slick.formatters.js"></script>
        <script src="SlickGrid/slick.editors.js"></script>
        <script src="SlickGrid/plugins/slick.cellrangedecorator.js"></script>
        <script src="SlickGrid/plugins/slick.cellrangeselector.js"></script>
        <script src="SlickGrid/plugins/slick.cellselectionmodel.js"></script>
        <script src="SlickGrid/slick.grid.js"></script>
        <script src="SlickGrid/slick.groupitemmetadataprovider.js"></script>
        <script src="SlickGrid/slick.dataview.js"></script>
        <script src="SlickGrid/controls/slick.pager.js"></script>
        <script src="SlickGrid/controls/slick.columnpicker.js"></script>

        <script>
            var myDataView,
                grid,
                checkboxSelector = new Slick.CheckboxSelectColumn({
//                    cssClass: "slick-cell-checkboxsel"
            }),
                dataTest = [],
                options = {
                editable: true,
                enableCellNavigation: true,
                asyncEditorLoading: false,
                autoEdit: false
            },
            columns = [
//                {id: "fixedTree", name: "Tree Name", field: "same"},
                checkboxSelector.getColumnDefinition(),
                {id: "sel", name: "#", field: "num", cssClass: "cell-selection", width: 40, resizable: false, selectable: false, focusable: false},
                {id: "title", name: "Title", field: "title", width: 70, minWidth: 50, cssClass: "cell-title", sortable: true, editor: Slick.Editors.Text},
                {id: "duration", name: "Duration", field: "duration", width: 70, sortable: true, groupTotalsFormatter: sumTotalsFormatter},
                {id: "%", name: "% Complete", field: "percentComplete", width: 80, formatter: Slick.Formatters.PercentCompleteBar, sortable: true, groupTotalsFormatter: avgTotalsFormatter},
                {id: "start", name: "Start", field: "start", minWidth: 60, sortable: true},
                {id: "finish", name: "Finish", field: "finish", minWidth: 60, sortable: true},
                {id: "cost", name: "Cost", field: "cost", width: 90, sortable: true, groupTotalsFormatter: sumTotalsFormatter},
                {id: "effort-driven", name: "Effort Driven", width: 80, minWidth: 20, maxWidth: 80, cssClass: "cell-effort-driven", field: "effortDriven", formatter: Slick.Formatters.Checkmark, sortable: true}
            ],
                options = {
                enableCellNavigation: true,
                editable: true
            },
            sortcol = "title",
                sortdir = 1,
                percentCompleteThreshold = 0,
                prevPercentCompleteThreshold = 0;


            function avgTotalsFormatter(totals, columnDef) {
                var val = totals.avg && totals.avg[columnDef.field];
                if (val != null) {
                    return "avg: " + Math.round(val) + "%";
                }
                return "";
            }

            function sumTotalsFormatter(totals, columnDef) {
                var val = totals.sum && totals.sum[columnDef.field];
                if (val != null) {
                    return "total: " + ((Math.round(parseFloat(val) * 100) / 100));
                }
                return "";
            }

            function myFilter(item, args) {
                return item["percentComplete"] >= args.percentComplete;
            }

            function percentCompleteSort(a, b) {
                return a["percentComplete"] - b["percentComplete"];
            }

            function comparer(a, b) {
                var x = a[sortcol], y = b[sortcol];
                return (x == y ? 0 : (x > y ? 1 : -1));
            }

            function groupByDuration() {
                myDataView.setGrouping({
                    getter: "duration",
                    formatter: function(g) {
                        return "Duration: " + g.value + " <span style='color:green'>(" + g.count + " items)</span>";
                    },
                    aggregators: [
                        new Slick.Data.Aggregators.Avg("percentComplete"),
                        new Slick.Data.Aggregators.Sum("cost")
                    ],
                    aggregateCollapsed: false,
                    lazyTotalsCalculation: true
                });
            }

            function groupByDurationEffortDrivenPercent() {
                myDataView.setGrouping([
                    {
                        getter: "duration",
                        formatter: function(g) {
                            return "Duration: " + g.value + " <span style='color:green'>(" + g.count + " items)</span>";
                        },
                        aggregators: [
                            new Slick.Data.Aggregators.Sum("duration"),
                            new Slick.Data.Aggregators.Sum("cost")
                        ],
                        aggregateCollapsed: true,
                        lazyTotalsCalculation: true
                    },
                    {
                        getter: "effortDriven",
                        formatter: function(g) {
                            return "Effort-Driven: " + (g.value ? "True" : "False") + " <span style='color:green'>(" + g.count + " items)</span>";
                        },
                        aggregators: [
                            new Slick.Data.Aggregators.Sum("duration"),
                            new Slick.Data.Aggregators.Sum("cost")
                        ],
                        lazyTotalsCalculation: true
                    },
                    {
                        getter: "percentComplete",
                        formatter: function(g) {
                            return "% Complete: " + g.value + " <span style='color:green'>(" + g.count + " items)</span>";
                        },
                        aggregators: [
                            new Slick.Data.Aggregators.Avg("percentComplete")
                        ],
                        aggregateCollapsed: true,
                        collapsed: true,
                        lazyTotalsCalculation: true
                    }
                ]);
            }

            function loadData(count) {
                var someDates = ["01/01/2009", "02/02/2009", "03/03/2009"];
                dataTest = [];
                // prepare the data
                for (var i = 0; i < count; i++) {
                    var d = (dataTest[i] = {});

                    d["same"] = "same";
                    d["id"] = "id_" + i;
                    d["num"] = i;
                    d["title"] = "Task " + i;
                    d["duration"] = Math.round(Math.random() * 30);
                    d["percentComplete"] = Math.round(Math.random() * 100);
                    d["start"] = someDates[ Math.floor((Math.random() * 2)) ];
                    d["finish"] = someDates[ Math.floor((Math.random() * 2)) ];
                    d["cost"] = Math.round(Math.random() * 10000) / 100;
                    d["effortDriven"] = (i % 5 == 0);
                }
                myDataView.setItems(dataTest);
            }


            $(".grid-header .ui-icon")
                .addClass("ui-state-default ui-corner-all")
                .mouseover(function(e) {
                $(e.target).addClass("ui-state-hover")
            }).mouseout(function(e) {
                $(e.target).removeClass("ui-state-hover")
            });

            $(function() {
                var groupItemMetadataProvider = new Slick.Data.GroupItemMetadataProvider();
                myDataView = new Slick.Data.DataView({
                    groupItemMetadataProvider: groupItemMetadataProvider,
                    inlineFilters: true
                });
                grid = new Slick.Grid("#myGrid", myDataView, columns, options);
                grid.setSelectionModel(new Slick.RowSelectionModel());
                grid.registerPlugin(checkboxSelector);

                // register the group item metadata provider to add expand/collapse group handlers
                grid.registerPlugin(groupItemMetadataProvider);
                grid.setSelectionModel(new Slick.CellSelectionModel());

                var pager = new Slick.Controls.Pager(myDataView, grid, $("#pager"));
                var columnpicker = new Slick.Controls.ColumnPicker(columns, grid, options);


                grid.onSort.subscribe(function(e, args) {
                    sortdir = args.sortAsc ? 1 : -1;
                    sortcol = args.sortCol.field;

                    if ($.browser.msie && $.browser.version <= 8) {
                        // using temporary Object.prototype.toString override
                        // more limited and does lexicographic sort only by default, but can be much faster

                        var percentCompleteValueFn = function() {
                            var val = this["percentComplete"];
                            if (val < 10) {
                                return "00" + val;
                            } else if (val < 100) {
                                return "0" + val;
                            } else {
                                return val;
                            }
                        };

                        // use numeric sort of % and lexicographic for everything else
                        myDataView.fastSort((sortcol == "percentComplete") ? percentCompleteValueFn : sortcol, args.sortAsc);
                    }
                    else {
                        // using native sort with comparer
                        // preferred method but can be very slow in IE with huge datasets
                        myDataView.sort(comparer, args.sortAsc);
                    }
                });

                // wire up model events to drive the grid
                myDataView.onRowCountChanged.subscribe(function(e, args) {
                    grid.updateRowCount();
                    grid.render();
                });

                myDataView.onRowsChanged.subscribe(function(e, args) {
                    grid.invalidateRows(args.rows);
                    grid.render();
                });


                var h_runfilters = null;

                // wire up the slider to apply the filter to the model
                $("#pcSlider,#pcSlider2").slider({
                    "range": "min",
                    "slide": function(event, ui) {
                        Slick.GlobalEditorLock.cancelCurrentEdit();

                        if (percentCompleteThreshold != ui.value) {
                            window.clearTimeout(h_runfilters);
                            h_runfilters = window.setTimeout(filterAndUpdate, 10);
                            percentCompleteThreshold = ui.value;
                        }
                    }
                });


                function filterAndUpdate() {
                    var isNarrowing = percentCompleteThreshold > prevPercentCompleteThreshold;
                    var isExpanding = percentCompleteThreshold < prevPercentCompleteThreshold;
                    var renderedRange = grid.getRenderedRange();

                    myDataView.setFilterArgs({
                        percentComplete: percentCompleteThreshold
                    });
                    myDataView.setRefreshHints({
                        ignoreDiffsBefore: renderedRange.top,
                        ignoreDiffsAfter: renderedRange.bottom + 1,
                        isFilterNarrowing: isNarrowing,
                        isFilterExpanding: isExpanding
                    });
                    myDataView.refresh();

                    prevPercentCompleteThreshold = percentCompleteThreshold;
                }

                // initialize the model after all the events have been hooked up
                myDataView.beginUpdate();
                myDataView.setFilter(myFilter);
                myDataView.setFilterArgs({
                    percentComplete: percentCompleteThreshold
                });
                debugger;
                loadData(10);
                groupByDuration();
//                groupByDurationEffortDrivenPercent();
                myDataView.endUpdate();

                $("#gridContainer").resizable();
            })
        </script>
    </body>
</html>