jqGrid 向特定列添加多 select 列过滤器

jqGrid add multi select column filter to a specific column

我正在尝试将多 select 过滤器添加到 jqGrid 中的 PROVIDER 列。我可以添加 select 过滤器,但现在我将其转换为 multi-select 过滤器。我在这里参考了一些旧帖子并尝试这样做。它没有给我任何错误,但它也没有创建 multi-select 过滤器。请让我知道我在下面做错了什么。 我能够获得唯一值并能够创建 SELECT 列表,我猜函数 dataInitMultiselect 有问题,因为我试图 console.log(elem) 但是它没有返回任何东西,甚至没有返回 undefined 但函数正在被调用,因为它没有抛出未定义的函数错误。

$("#home_grid").jqGrid({
        url: "/URL_TO_FETCH_DATA",
        datatype: "json",
        mtype: "GET",
        colNames: ["Provider", "Title","Original Publish Time", "Fetch Time"],
        colModel:
        [
            {
                name    : "PROVIDER",
                align   : "center",
                width   : "120%",
                search  : true
            },
            {
                name    : "TITLE",
                align   : "center",
                search  : true,
                width   : "250%",
                formatter: Title_Url_Bind 
            },
            {
                name        : "PUBLISH_TIME",
                align       : "center",
                width       : "130%",
                search      : true,
                sorttype    : "datetime"

            },
            {
                name        : "DB_ENTRY_TIME",
                align       : "center",
                width       : "130%",
                sortable    : true,
                sorttype    : "datetime"
            }
        ],
        pager       : "#home_pager",
        loadonce    : true,
        shrinkToFit : true,
        rowNum      : 10,
        autoHeight  : true,
        rowList     : [10, 15, 20, 25, 50],
        sortable    : true,
        viewrecords : true,
        toolbar     : [true, "top"],
        autowidth   : true,
        beforeProcessing: beforeProcessingHandler1,
    });

    function beforeProcessingHandler1(data) {
        initializeGridFilterValueDem(data);
    }

    initializeGridFilterValueDem = function (data) {
        setSearchSelect("Provider", jQuery("#home_grid"), data);
    }

    setSearchSelect = function (columnName, grid,data) {
        grid.jqGrid('setColProp', columnName,
            {
                searchoptions: {
                    clearSearch: false,
                    sopt: ['eq', 'ne'],
                    value: buildSearchSelect(getUniqueNames(columnName, data,grid)),
                    attr: { multiple: 'multiple', size: 7},
                    dataInit: dataInitMultiselect
                }
            }
        );
    }

    buildSearchSelect = function (uniqueNames) {
        var values = "";
        $.each(uniqueNames, function () {
            values += this + ":" + this + ";";
        });
        return values.substring(0, values.length - 1);
    }

    getUniqueNames = function (columnName, mydata_parm, grid) {

        var mydata = grid.jqGrid("getGridParam", "data");

        var texts = $.map(mydata, function (item) {
            return item[columnName];
        }),

        uniqueTexts = [], textsLength = texts.length, text, textsMap = {}, i;

        for (i = 0; i < textsLength; i++) {
            text = texts[i];
            if (text !== undefined && textsMap[text] === undefined) {
                // to test whether the texts is unique we place it in the map.
                textsMap[text] = true;
                uniqueTexts.push(text);
            }
        }

        return uniqueTexts;
    }

    dataInitMultiselect = function (elem) {
        console.log(elem);
        setTimeout(function () {
            var $elem = $(elem), id = elem.id,
                inToolbar = typeof id === "string" && id.substr(0, 3) === "gs_",
                options = {
                    selectedList: 2,
                    height: "auto",
                    checkAllText: "all",
                    uncheckAllText: "no",
                    noneSelectedText: "Any",
                    open: function () {
                        var $menu = $(".ui-multiselect-menu:visible");
                        $menu.width("auto");
                        return;
                    }
                },
                $options = $elem.find("option");
            if ($options.length > 0 && $options[0].selected) {
                $options[0].selected = false; // unselect the first selected option
            }
            if (inToolbar) {
                options.minWidth = 'auto';
            }
            //$elem.multiselect(options);
            $elem.multiselect(options).multiselectfilter({ placeholder: '' });
            $elem.siblings('button.ui-multiselect').css({
                width: inToolbar ? "98%" : "100%",
                marginTop: "1px",
                marginBottom: "1px",
                paddingTop: "3px"
            });
        }, 50);

    };

非常感谢您的回复,是的,我正在使用免费的 jqGrid。 根据提到的评论,我尝试更改代码但仍然不适合我。请在下面找到更新后的代码,我尝试按照 jqGrid MultiSelect Demo

中所述进行操作

但是它向我抛出错误 Uncaught ReferenceError: multiselectTemplate is not defined,请告诉我如何解决这个问题。 由于他们使用本地数据加载 jqgrid,我发现很难解决这个问题。

    //FUNCTION TO POPULATE THE TABLE WITH THE DATA
function Grid_Table_Populator()
{
    //Populdate the Datatable with the WEB Feed data
    $("#home_grid").jqGrid({
        url: "/Web_Feed_Data",
        datatype: "json",
        mtype: "GET",
        colNames: ["ID", "PROVIDER", "Title"],
        colModel:
        [
            {
                name    : "ID",
                align   : "center",
                search  : true,
                hidden  : true
            },
            {
                name    : "PROVIDER",
                align   : "center",
                width   : "120%",
                type    : "text", 
                search  : true, 
                template: multiselectTemplate       
            },
            {
                name    : "TITLE",
                align   : "center",
                search  : true,
                width   : "250%",
                formatter: Title_Url_Bind 
            },
        ],
        pager       : "#home_pager",
        loadonce    : true,
        shrinkToFit : true,
        rowNum      : 10,
        autoHeight  : true,
        rowList     : [10, 15, 20, 25, 50],
        sortable    : true,
        sortname    : "TITLE",
        sortorder   : "desc",
        viewrecords : true,
        toolbar     : [true, "top"],
        autowidth   : true,
        caption     : 'Table Data',
        loadComplete: function(data)
        {
            if (!this.ftoolbar) {
                // create filter toolbar if it isn't exist 
                $(this).jqGrid("filterToolbar", {       
                    defaultSearch: "cn",
                    beforeClear: function() {
                    $(this.grid.hDiv)
                        .find(".ui-search-toolbar button.ui-multiselect")
                        .each(function() {
                            $(this).prev("select[multiple]").multiselect("refresh");
                        });
                    }
                });
                $(this).triggerHandler("jqGridRefreshFilterValues");
                $(this.grid.hDiv)
                    .find(".ui-search-toolbar button.ui-multiselect")
                    .each(function() {
                    $(this).prev("select[multiple]")
                        .multiselect("refresh");
                });        
            }
        },
    }); 

    dataInitMultiselect = function (elem, searchOptions) {
        var $grid = $(this);
            setTimeout(function() {
                var $elem = $(elem),
                    id = elem.id,
                    inToolbar = searchOptions.mode === "filter",
                    options = {
                        selectedList: 2,
                        height: "auto",
                        checkAllText: "all",
                        uncheckAllText: "no",
                        noneSelectedText: "Any",
                        open: function() {
                            var $menu = $(".ui-multiselect-menu:visible");
                            $menu.width("auto");
                            var height = $menu.find(">ul>li").first().outerHeight();
                            $menu.find(">ul").css("maxHeight", 5 * Math.max(height, 12));
                            return;
                        }
                    },
                    $options = $elem.find("option");
                if ($options.length > 0 && $options[0].selected) {
                    $options[0].selected = false; // unselect the first selected option

                }
                if (inToolbar) {
                    options.minWidth = "auto";
                }
                $grid.triggerHandler("jqGridRefreshFilterValues");
                $elem.multiselect(options);
                // replace icons ui-icon-check, ui-icon-closethick, ui-icon-circle-close
                // and ui-icon-triangle-1-s to font awesome icons
                var $header = $elem.data("echMultiselect").header;
                $header.find("span.ui-icon.ui-icon-check")
                    .removeClass("ui-icon ui-icon-check")
                    .addClass("fa fa-fw fa-check");
                $header.find("span.ui-icon.ui-icon-closethick")
                    .removeClass("ui-icon ui-icon-closethick")
                    .addClass("fa fa-fw fa-times");
                $header.find("span.ui-icon.ui-icon-circle-close")
                    .removeClass("ui-icon ui-icon-circle-close")
                    .addClass("fa fa-times-circle");
                $elem.data("echMultiselect")
                    .button
                    .find("span.ui-icon.ui-icon-triangle-1-s")
                    .removeClass("ui-icon ui-icon-triangle-1-s")
                    .addClass("fa fa-caret-down")
                    .css({
                        float: "right",
                        marginRight: "5px"
                    });

                $elem.siblings("button.ui-multiselect").css({
                    width: "100%",
                    margin: "1px 0",
                    paddingTop: ".3em",
                    paddingBottom: ".3em"
                });
            }, 50);
        },    
        multiselectTemplate = {
            stype: "select", 
            searchoptions: {
                generateValue: true,
                //noFilterText: "Any",
                sopt: ["in"],
                attr: {
                    multiple: "multiple",
                    size: 3
                },
                dataInit: dataInitMultiselect
            }
    };
}

我尝试在函数内和函数外声明它,但仍然没有成功。请帮我解决这个问题。

在 Oleg 的大力帮助下,我获得了 Multi-Select,但它无法正常工作。当我单击它时,它不会展开并显示该选项。我已经在这里发布了我的代码 MY JQGRID CODE@Oleg 你能看看这个并为我提供解决方案吗?

我的 jqGrid 看起来像这样:

从您的其他问题可以看出您使用的是免费的 jqGrid 分支。它支持自动生成唯一值。因此可以使用

searchoptions: {
    generateValue: true,
    sopt: ["in"],
    attr: { multiple: "multiple", size: 7 },
    dataInit: dataInitMultiselect
}

而不是

searchoptions: {
    clearSearch: false,
    sopt: ['eq', 'ne'],
    value: buildSearchSelect(getUniqueNames(columnName, data,grid)),
    attr: { multiple: 'multiple', size: 7},
    dataInit: dataInitMultiselect
}

只有在加载数据后才会填充列中数据的唯一值,这一点很重要。然后应该在从服务器加载数据后创建或重新创建 filterToolbar 。例如,可以在 loadComplete 中测试 this.ftoolbar 来检测 filterToolbar 是否已经存在:

loadComplete: function () {
    if (!this.ftoolbar) {
        // create filter toolbar if it isn't exist 
        $(this).jqGrid("filterToolbar", {
            defaultSearch: "cn",
            beforeClear: function() {
                $(this.grid.hDiv)
                    .find(".ui-search-toolbar button.ui-multiselect")
                    .each(function() {
                    $(this).prev("select[multiple]").multiselect("refresh");
                });
            }
        });
        $(this).triggerHandler("jqGridRefreshFilterValues");
        $(this.grid.hDiv)
            .find(".ui-search-toolbar button.ui-multiselect")
            .each(function() {
            $(this).prev("select[multiple]")
                .multiselect("refresh");
        });        
    }
}

演示 https://jsfiddle.net/OlegKi/ty4e68pm/2/ 展示了在免费 jqGrid 中使用 multiselect 的可能实现。函数 dataInitMultiselect 具有以下实现:

var dataInitMultiselect = function (elem, searchOptions) {
        var $grid = $(this);
        setTimeout(function() {
            var $elem = $(elem),
                id = elem.id,
                inToolbar = searchOptions.mode === "filter",
                options = {
                    selectedList: 2,
                    height: "auto",
                    checkAllText: "all",
                    uncheckAllText: "no",
                    noneSelectedText: "Any",
                    open: function() {
                        var $menu = $(".ui-multiselect-menu:visible");
                        $menu.width("auto");
                    }
                },
                $options = $elem.find("option");
            if ($options.length > 0 && $options[0].selected) {
                $options[0].selected = false; // unselect the first selected option

            }
            if (inToolbar) {
                options.minWidth = "auto";
            }
            $grid.triggerHandler("jqGridRefreshFilterValues");
            $elem.multiselect(options);
            // replace icons ui-icon-check, ui-icon-closethick, ui-icon-circle-close
            // and ui-icon-triangle-1-s to font awesome icons
            var $header = $elem.data("echMultiselect").header;
            $header.find("span.ui-icon.ui-icon-check")
                .removeClass("ui-icon ui-icon-check")
                .addClass("fa fa-fw fa-check");
            $header.find("span.ui-icon.ui-icon-closethick")
                .removeClass("ui-icon ui-icon-closethick")
                .addClass("fa fa-fw fa-times");
            $header.find("span.ui-icon.ui-icon-circle-close")
                .removeClass("ui-icon ui-icon-circle-close")
                .addClass("fa fa-times-circle");
            $elem.data("echMultiselect")
                .button
                .find("span.ui-icon.ui-icon-triangle-1-s")
                .removeClass("ui-icon ui-icon-triangle-1-s")
                .addClass("fa fa-caret-down")
                .css({
                    float: "right",
                    marginRight: "5px"
                });

            $elem.siblings("button.ui-multiselect").css({
                width: "100%",
                margin: "1px 0",
                paddingTop: ".3em",
                paddingBottom: ".3em"
            });
        }, 50);
    };

更新: 我分析了你的演示 https://jsfiddle.net/B_AV_B/7ecrmtz4/5/。它包含很多错误:

  1. 您在 multiselect 列中缺少 stype : "select"。搜索字段必须具有 select 类型 (stype : "select") 才能显示为 <select> 元素,稍后可以根据 multiselect control
  2. 我多次写信给你关于插入 只有一个 版本的 jQuery 和其他 JavaScript 库的重要性。此外,根据依赖关系保持插入的 JS 文件的顺序很重要。 Multiselect 小部件是 jQuery UI 的插件。因此必须在jQuery UI 之前插入。总之你应该更换
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-ui-multiselect-widget/2.0.2/jquery.multiselect.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>   

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-ui-multiselect-widget/2.0.2/jquery.multiselect.js"></script>
  1. 您应该删除 ../bootstrap-multiselect/0.9.13/js/bootstrap-multiselect.js覆盖 multiselect 之前注册的。
  2. JavaScript 区分大小写。输入数据的 ID 属性 似乎指定了每个输入项的唯一 ID。 jqGrid 默认使用 id 而不是 ID。如果你使用 datatype: "local" 那么你应该包括 localReader: { id: "ID" } 参数。如果您使用 datatype: "json",那么您应该包括 jsonReader: { id: "ID" }。在您的情况下,您可以包含这两个参数。
  3. 您使用了错误的 open 回调代码(将您的代码与我的回答中的代码进行比较)。将它用作 var $menu = $(".ui-multiselect-menu:visible"); $menu.width("auto"); 就足够了,无需其他操作,这会使其他一些项目不可见。
  4. width 属性 在 colModel 上的值应该是数字而不是像 "120%" 这样的字符串。数字将被解释为像素。如果您使用 autowidth : true,初始 width 值将按比例增加,以使网格的宽度等于外部元素的宽度。
  5. 最后,我向您的演示添加了一些 CSS 规则
.ui-multiselect-menu .ui-multiselect-header ul,
.ui-multiselect-menu .ui-multiselect-checkboxes li {
    font-size: 12px;
}

.ui-multiselect-menu .ui-multiselect-header a:hover {
    text-decoration: none;
}
.ui-multiselect-menu .ui-multiselect-close {
    margin-right: 3px;
}

您可以根据您的要求修改font-size上面的规则。

修改后的演示是https://jsfiddle.net/OlegKi/teLja6z3/25/