1

I have looked at all of the Q & A about the use of the Multiselect widget in the filter toolbar of jqGrid. I have noticed that in almost all the solutions, the jqGrid versions and the jquery versions are not current ones. I am using the most current versions of both jqGrid (4.13.4) and jquery (3.1.1) and jqueryUI (1.12.1).

I have tried the sample code from here in my javascript. It loads fine, but when I try to choose any of the values from the multiselect, the grid clears and remains cleared even when deselecting the values from the multiselect.

I just want to make sure that this solution works with the most current versions of free-jqGrid, jquery, and jqueryUI that I am using.

Jerry P
  • 49
  • 6

2 Answers2

1

I posted an example of the usage of Multiselect widget in free jqGrid in the old answer. The later versions of free jqGrid suports "in" operation, which is very practical in case of usage Multiselect widget.

I created the new demo for you, which looks like on the picture below.

enter image description here

It loads the input data from testJsonData.json, find all unique values for ship_via column inside of beforeProcessing and set the searchoptions.value built based on the values. The demo uses the latest code of free jqGrid from GitHub (it's more recent as 4.13.4). I plan to publish soon the curent code from GitHub as 4.13.5 or 4.14.0. the demo uses the current v1.17 version of Multiselect widget creates by Eric Hyndse. The code of the demo is

var getUniqueNames = function (columnName, mydata) {
        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;
    },
    buildSearchSelect = function (uniqueNames) {
        var values = "";
        $.each(uniqueNames, function () {
            values += this + ":" + this + ";";
        });
        return values.slice(0, -1);
    },
    initMultiselect = function (searchOptions) {
        var $elem = $(searchOptions.elem),
        options = {
            selectedList: 2,
            height: "auto",
            checkAllText: "all",
            uncheckAllText: "no",
            noneSelectedText: "Any",
            open: function () {
                var $menu = $(".ui-multiselect-menu:visible");
                $menu.addClass("ui-jqdialog").width("auto");
                $menu.find(">ul").css("maxHeight", "200px");
            }
        };
        if (searchOptions.mode === "filter") {
            options.minWidth = "auto";
        }
        $elem.multiselect(options);
        $elem.siblings("button.ui-multiselect").css({
            width: "100%",
            margin: "1px 0",
            paddingTop: ".3em",
            paddingBottom: "0"
        });
    },
    setSearchSelect = function (columnName, data) {
        var values = buildSearchSelect(getUniqueNames.call(this, columnName, data));
        $(this).jqGrid("setColProp", columnName, {
            stype: "select",
            searchoptions: {
                value: values,
                sopt: ["in"],
                attr: {
                    multiple: "multiple",
                    size: 4
                },
                selectFilled: initMultiselect
            }
        });
    },
    myDefaultSearch = "cn",
    beforeProcessingHandler1 = function (data) {
        var $this = $(this), p = $this.jqGrid("getGridParam");
        // !!! it will be called only after loading from the server
        // datatype is always "json" here
        setSearchSelect.call(this, "ship_via", data);

        if (this.ftoolbar === true) {
            // if the filter toolbar is not already created
            $("#gs_" + this.id + "ship_via").multiselect("destroy");
            $this.jqGrid('destroyFilterToolbar');
        }

        if (p.postData.filters) {
            p.search = true;
        }

        $this.jqGrid("filterToolbar", {
            //stringResult: true,
            defaultSearch: myDefaultSearch,
            beforeClear: function () {
                $(this.grid.hDiv)
                .find(".ui-search-toolbar button.ui-multiselect")
                .each(function () {
                    $(this).prev("select[multiple]").multiselect("refresh");
                });
            }
        });
    };

$("#list").jqGrid({
    url: "testJsonData.json",
    datatype: "json",
    colNames: ["Client", "Amount", "Tax", "Total", "Shipped via", "Notes"],
    colModel: [
        { name: "name", width: 65 },
        { name: "amount", width: 75, template: "number" },
        { name: "tax", width: 52, template: "number" },
        { name: "total", width: 65, template: "number" },
        { name: "ship_via", width: 85, align: "center" },
        { name: "note", width: 100, sortable: false }
    ],
    rowNum: 5,
    sortname: "name",
    iconSet: "fontAwesome",
    autoencode: true,
    loadonce: true,
    forceClientSorting: true, // local sorting and filtering data loaded from the server
    beforeProcessing: beforeProcessingHandler1,
    rowList: [5, 10, 20, 30, 100],
    pager: true,
    pagerRightWidth: 120, // fix wrapping or right part of the pager
    viewrecords: true,
    sortable: true
}).jqGrid("navGrid", { add: false, edit: false, del: false, search: false });
Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • thanks for the quick reply. That fixed the issues I was seeing in my code. The only thing I need to do now is to be able to display a list of values in the multiselect of my choosing rather than of the existing values in the column and to also display the label rather than the value in the multiselect because I am using value pairs for the select options when the line is in edit mode. Would it be possible to use the existing list of values I use in the edit mode select options to feed to the multiselect its values? – Jerry P Oct 25 '16 at 13:49
  • @JerryP: Yes of cause. `setSearchSelect` first calls `buildSearchSelect(getUniqueNames.call(this, columnName, data));` to generate the `searchoptions.value` and then uses `setColProp` to change the column properties. You can just use the properties `{ stype: "select", searchoptions: { value: values, sopt: ["in"], attr: { multiple: "multiple", size: 4 }, selectFilled: initMultiselect }` directly in the column where you need to set multiselect wigdet. – Oleg Oct 25 '16 at 16:13
  • in the code you supplied above, when "any" is selected after clearing all the checkboxes, the grid returns nothing instead of all the records. I'm having the same issue in my code. – Jerry P Oct 25 '16 at 19:52
  • @JerryP: If one choose "all", then all possible entries will be selected and the grid will display all the data. "all" produce the filter "ship_via" IN ["TN", "FE", "ABR", "CNC"]. By clicking on "no" one uses the filter "ship_via" IN []. No row corresponds the filter and thus the empty grid will be displayed. One can change the filter a little by usage `beforeSearch` callback of `filterToolbar`. See [the answer](http://stackoverflow.com/a/8953934/315935). – Oleg Oct 25 '16 at 20:08
  • @JerryP: Moreover you can use your custom filter operation instead of `"IN"`. See [the answer](http://stackoverflow.com/a/28615923/315935) or [this one](http://stackoverflow.com/a/29676941/315935) and [the wiki article](https://github.com/free-jqgrid/jqGrid/wiki/Custom-filtering-searching-Operation) – Oleg Oct 25 '16 at 20:08
  • I guess I thought the "no" option was more like a "clear" option that would remove that field's criteria from the filter. Also, since the "any" shows when you click on "no", to me, "any" means all by default like when the grid is first loaded. – Jerry P Oct 25 '16 at 20:48
  • @JerryP: I understand that the behavior of "no" option is probably not perfect, but you can easy change it by usage `beforeSearch` callback of `filterToolbar`. It has `this` as the DOM of the grid, `$(this).jqGrid("getGridParam")` or `this.p` represent object with all jqGrid parameters. Thus `this.p.postData.filters` is the filter, which you can modify in any way. – Oleg Oct 25 '16 at 20:56
0

Here's the fix for the "Any" option in the drop down to return all the options in the select control.

Modify this section of the code:

modifySearchingFilter = function (separator) {
var i, l, rules, rule, parts, j, group, str,
    filters = $.parseJSON(this.p.postData.filters);
console.log(filters);
rules = filters.rules;
console.log(rules.length)
for (i = 0; i < rules.length; i++) {
    rule = rules[i];
    if (rule.data == "") {
        rule.op = "ne"; //this will return anything not equal to ""
    }
}
console.log("after splicing: " + JSON.stringify(filters))
this.p.postData.filters = JSON.stringify(filters);},

The important part if to add the check of the rules and return a not equal ("ne") for the operator. This will create a rule that filters out all options that are not equal to an empty string. This should return all the select options, in other words, reset the select to it's initial state which shows all the options in the select and it will return all the records in the grid. Hope this helps in the future.

Jerry P
  • 49
  • 6