让slickgrid处理大型数据集的分页、复选框选择、排序和过滤



我设置了一个光滑的网格,并试图将500,000条记录传递给它或更少(500k是绝对最大值)。

分页、排序、内联列过滤和复选框行选择都设置好了,并使用了一些注意事项。

浏览器崩溃或询问(你确定要继续运行这个长时间运行的脚本吗?)每当我在IE8和任何FireFox实例中加载任何超过100k记录的数据时。(IE8是在我所在的公司范围内使用的,所以我现在没有选择告诉他们升级)

我使用MVC,数据来自多个ajax请求,因为json数据只能这么长。

我想要的效果是,当用户从"ddlFiles"中选择一个文件时,网格将根据选择的结果填充。

前端代码如下:

<script type="text/javascript">
    var grid;
    var finalData = [];
    var columnFilters = {};
    function getDate(jsonDate) {
        // added checks for undefs.. djweaver 
        if (typeof jsonDate === 'undefined') {
            return "01/01/0000";
        }
        var dt1 = new Date(parseInt(jsonDate.substring(6, jsonDate.length - 2)));
        var month = (dt1.getMonth() + 1);
        var day = dt1.getDate();
        var year = dt1.getFullYear();
        if (month < 10) { month = "0" + month; }
        if (day < 10) { day = "0" + day; }
        var dt1String = month + "/" + day + "/" + year;
        return dt1String;
    }
    $("#myGrid").height(($("#ddlPage").val() * 25) + 59);
    $("#ddlClients").change(function () {
        $("#loadingDialog").dialog('open');
        $("#progressbar").fadeIn('fast');
        if (finalData.length > 0) {
            grid.destroy();
        }
        while (finalData.length > 0) {
            finalData.pop();
        }
        setTimeout(function () {
            $("#ddlFiles").val(0);
            $("#myGrid").empty();
            $("#loadingDialog").dialog('close');
            $("#progressbar").fadeOut('fast');
        }, 5000);
    });
    $("#ddlFiles").change(function () {
        if ($("ddlFiles").val() != 0) {
            if (finalData.length > 0) {
                grid.destroy();
            }
            while (finalData.length > 0) {
                finalData.pop();
            }
            $("#myGrid").empty();
            $(".selEdit").show();
            $("#loadingDialog").dialog('open');
            $("#progressbar").fadeIn('slow');
            $.ajax({
                type: "GET",
                url: "Intake/getDataInfo",
                dataType: "text",
                data: { numRecords: $("#ddlFiles").val() },
                cache: false,
                success: function (info) {
                    var counter = (info / 5000) + 1;
                    for (var x = 0; x <= counter + 1; x++) {
                        $.ajax({
                            type: "GET",
                            url: "Intake/getData",
                            dataType: "json",
                            data: { counter: x },
                            cache: false,
                            success: function (json) {
                                $.merge(finalData, json);
                            }
                        });
                    }
                    waitOnData(info);
                }
            });
        }
    });
    var timeoutId = null;
    function waitOnData(totalCount) {
        var percent = (finalData.length / totalCount)*100;
        $("#progressbar").width(percent + "%");
        if (percent < 100) {
            timeoutId = setTimeout(function () {
                waitOnData(totalCount);
            }, 300);
        } else {
            popGrid(finalData);
        }
    }
    function popGrid(data) {
        var dateFormatter = function (row, cell, value, columnDef, dataContext) {
            return getDate(value);
        };
        var dataView; 
        var columns = [];
        var checkboxSelector = new Slick.CheckboxSelectColumn({});
        columns.push(checkboxSelector.getColumnDefinition());
        columns.push(
            { id: "LastName", name: "Last Name", field: "LastName", sortable: true, width: 75 },
            { id: "FirstName", name: "First Name", field: "FirstName", sortable: true, width: 75 },
            { id: "Hicn", name: "Hicn", field: "Hicn", sortable: true, width: 75 },
            { id: "DOB", name: "DOB", field: "DOB", sortable: true, formatter: dateFormatter, width: 75 },
            { id: "PlanEffDate", name: "Plan Eff Date", field: "PlanEffDate", formatter: dateFormatter, sortable: true, width: 80 },
            { id: "PrimaryCarrier", name: "Primary Carrier", field: "PrimaryCarrier", sortable: true, width: 100 },
            { id: "SecondaryCarrier", name: "Secondary Carrier", field: "SecondaryCarrier", sortable: true, width: 100 },
            { id: "SecondaryId", name: "SecondaryId", field: "SecondaryId", sortable: true, width: 80 }
        );
        var options = {
            editable: true,
            multiColumnSort: false,
            enableCellNavigation: true,
            showHeaderRow: true,
            headerRowHeight: 30,
            asyncEditorLoading: true,
            forceFitColumns: true,
            explicitInitialization: true
        };
        function filter(item) {
            for (var columnId in columnFilters) {
                if (columnId !== undefined && columnFilters[columnId] !== "") {
                    var c = grid.getColumns()[grid.getColumnIndex(columnId)];
                    var itemString = item[c.field].toString();
                    if (itemString.indexOf('/Date') >= 0) { itemString = getDate(itemString) }
                    if (itemString.toLowerCase().lastIndexOf(columnFilters[columnId].toString().toLowerCase(),0) === -1) {
                        return false;
                    }
                }
            }
            return true;
        }        
        dataView = new Slick.Data.DataView({ inlineFilters: true });
        grid = new Slick.Grid("#myGrid", dataView, columns, options);
        var columnpicker = new Slick.Controls.ColumnPicker(columns, grid, options);
        grid.setSelectionModel(new Slick.RowSelectionModel({ selectActiveRow: false }));
        grid.registerPlugin(checkboxSelector);
        var pager = new Slick.Controls.Pager(dataView, grid, $("#pager"));
        dataView.onRowCountChanged.subscribe(function (e, args) {
            grid.updateRowCount();
            grid.render();
        });
        dataView.onRowsChanged.subscribe(function (e, args) {
            grid.invalidateRows(args.rows);
            grid.render();
        });
        grid.onHeaderRowCellRendered.subscribe(function (e, args) {
            $(args.node).empty();
            if (args.column.id != "_checkbox_selector") {
                $("<input type='text'>")
                                            .data("columnId", args.column.id)
                                            .val(columnFilters[args.column.id])
                                            .appendTo(args.node);
            }
        });
        $(grid.getHeaderRow()).delegate(":input", "change keyup", function (e) {
            var columnId = $(this).data("columnId");
            if (columnId != null) {
                columnFilters[columnId] = $.trim($(this).val());
                dataView.refresh();
            }
        });
        grid.onHeaderRowCellRendered.subscribe(function (e, args) {
            $(args.node).empty();
            if (args.column.id != "_checkbox_selector") {
                $("<input type='text'>")
                                .data("columnId", args.column.id)
                                .val(columnFilters[args.column.id])
                                .appendTo(args.node);
            }
        });
        grid.onSort.subscribe(function (e, args) {
            var isDate = (finalData[0][args.sortCol.field].indexOf("/Date") >= 0) ? true : false;
            dataView.fastSort(args.sortCol.field, isDate, args.sortAsc);
            //grid.invalidate(); 
            $("#progressbar").fadeOut('fast');
            $("#loadingDialog").dialog('close');
        });
        dataView.syncGridSelection(grid, true);
        grid.init();
        dataView.beginUpdate();
        dataView.setItems(data, "Id");
        dataView.setFilter(filter);
        dataView.setPagingOptions({ pageSize: $("#ddlPage").val() });
        dataView.endUpdate();
        $("#progressbar").fadeOut('fast');
        $("#loadingDialog").dialog('close');
    }
    $("#chkPage").click(function () {
        grid.setSelectedRows("0,1,2,3,4");
        alert($.session.get("selected"));
    });
    function SetPager() {
        $('#txtPagingChange').keyup(function () {
            var number = $("#txtPagingChange").val();
            dataView.setPagingOptions({ pageNum: number - 1 });
            $('#txtPagingChange').focus();
            $('#txtPagingChange').val('');
            $('#txtPagingChange').val(number);
        });
    }
    $(function () {
        $(".selEdit").hide();
        $("#btnConfigs").click(function () {
            $("#ConfigDialog").dialog('open');
        });
        $("#ConfigDialog").dialog({
            autoOpen: false,
            modal: true,
            width: 350,
            height: 135,
            closeOnEscape: false,
            beforeclose: function (event, ui) { return false; },
            dialogClass: "noclose",
            show: {
                effect: "slide",
                duration: 1000
            },
            hide: {
                effect: "fold",
                duration: 1000
            }
        });
        $("#btnOverrideConfirm").dialog({
            autoOpen: false,
            modal: true,
            width: 400,
            height: 135,
            closeOnEscape: false,
            beforeclose: function (event, ui) { return false; },
            dialogClass: "noclose",
            show: {
                effect: "slide",
                duration: 1000
            },
            hide: {
                effect: "fold",
                duration: 1000
            }
        });
        $("#btnSubmitGrid").click(function () {
            $("#btnOverrideConfirm").dialog('open');
        });
        $("#btnSubmitConfig").click(function () {
            $("#myGrid").height(($("#ddlPage").val() * 25) + 59);
            dataView.setPagingOptions({ pageSize: $("#ddlPage").val() });
            $("#ConfigDialog").dialog('close');
        });
        $("#progressbar").progressbar({ value: false });
        $("#loadingDialog").dialog({
            autoOpen: false,
            modal: true,
            width: 730,
            height: 100,
            closeOnEscape: false,
            beforeclose: function (event, ui) { return false; },
            dialogClass: "noclose",
            show: {
                effect: "puff",
                duration: 10
            },
            hide: {
                effect: "slide",
                duration: 10
            }
        });
    })
</script>

我同意la ghiscoding的建议,您必须在数据上实现惰性加载。

这里只是一个关于如何实现分页的想法(不使用Slick.Controls.Pager):

  • 实现后端数据的分页/限制,只传递ajax请求的页码
  • 在前端部分
  • 中,首先获取分页信息(总数目)。行数,总数目。的页面)
  • 为上一页和下一页添加2个按钮,当点击上一页/下一页按钮时,获取数据并传递页码(当前页面减去/加1),当没有更多的上一页/下一页时禁用上一页/下一页
  • 将当前页面保存在javascript的全局变量/对象中
  • 每次获取后刷新网格(网格只包含并显示当前页面的行)

这样做意味着你不必渲染/获取所有数据并将其存储到网格中。然而,你可以对网格中的数据做的其他功能也正在部分完成(例如,排序只能对网格中的当前项进行排序,而不能对所有最终数据进行排序)

最新更新