自定义Kendo下拉菜单多选以使用复选框

时间:2014-08-09 20:42:22

标签: jquery checkbox kendo-ui telerik kendo-grid

我使用从Telerik论坛收集的一些自定义代码来修改Kendo奇怪的内置多选小部件以改为使用复选框。

//MultiSelect - A user extension of KendoUI DropDownList widget.
(function ($) {
    // shorten references to variables
    var kendo = window.kendo,
        ui = kendo.ui,
        DropDownList = ui.DropDownList,
        keys = kendo.keys,
        SELECT = "select",
        SELECTIONCHANGED = "selectionChanged",
        SELECTED = "k-state-selected",
        HIGHLIGHTED = "k-state-active",
        CHECKBOX = "custom-multiselect-check-item",
        SELECTALLITEM = "custom-multiselect-selectAll-item",
        MULTISELECTPOPUP = "custom-multiselect-popup",
        EMPTYSELECTION = "custom-multiselect-summary-empty";

    var lineTemplate = '<input type="checkbox" name="#= {1} #" value="#= {0} #" class="' + CHECKBOX + '" />' +
                    '<span data-value="#= {0} #">#= {1} #</span>';

    var MultiSelectBox = DropDownList.extend({
        init: function (element, options) {
            options.template = kendo.template(kendo.format(lineTemplate, options.dataValueField, options.dataTextField));
            // base call to widget initialization
            DropDownList.fn.init.call(this, element, options);
        },
        options: {
            name: "MultiSelectBox",
            index: -1,
            showSelectAll: null,
            preSummaryCount: 1,  // number of items to show before summarising
            emptySelectionLabel: '',  // what to show when no items are selected
            selectionChanged: null, // provide callback to invoke when selection has changed
        },
        events: [
            SELECTIONCHANGED
        ],
        refresh: function () {
            // base call
            DropDownList.fn.refresh.call(this);
            this._updateSummary();
            $(this.popup.element).addClass(MULTISELECTPOPUP);
        },
        current: function (candidate) {
            return this._current;
        },
        open: function () {
            this._removeSelectAllItem();
            this._addSelectAllItem();
            DropDownList.fn.open.call(this);
            //hook on to popup event because dropdown close does not
            //fire consistently when user clicks on some other elements
            //like a dataviz chart graphic
            this.popup.one('close', $.proxy(this._onPopupClosed, this));
        },
        _onPopupClosed: function () {
            this._removeSelectAllItem();
            this._current = null;
            //this._highlightCurrent();
            this._raiseSelectionChanged();
        },
        _raiseSelectionChanged: function () {
            var currentValue = this.value();
            var currentValues = $.map((currentValue.length > 0 ? currentValue.split(",") : []).sort(), function (item) { return item.toString(); });
            var oldValues = $.map((this._oldValue || []).sort(), function (item) { return item.toString(); });
            // store for next pass
            this._oldValue = $.map(currentValues, function (item) { return item.toString(); });
            var changedArgs = { newValue: currentValues, oldValue: oldValues };
            if (oldValues) {
                var hasChanged = ($(oldValues).not(currentValues).length == 0 && $(currentValues).not(oldValues).length == 0) !== true;
                if (hasChanged) {
                    //if (this.options.selectionChanged)
                    //    this.options.selectionChanged(changedArgs);
                    this.trigger(SELECTIONCHANGED, changedArgs);
                }
            }
            else if (currentValue.length > 0) {
                //if (this.options.selectionChanged)
                //    this.options.selectionChanged(changedArgs);
                this.trigger(SELECTIONCHANGED, changedArgs);
            }
        },
        _addSelectAllItem: function () {
            if (!this.options.showSelectAll) return;
            var firstListItem = this.ul.children('li:first');
            if (firstListItem.length > 0) {
                this.selectAllListItem = $('<li tabindex="-1" role="option" unselectable="on" class="k-item ' + SELECTALLITEM + '"></li>').insertBefore(firstListItem);
                // fake a data object to use for the template binding below
                var selectAllData = {};
                selectAllData[this.options.dataValueField] = '*';
                selectAllData[this.options.dataTextField] = 'All';
                this.selectAllListItem.html(this.options.template(selectAllData));
                this._updateSelectAllItem();
                this._makeUnselectable(); // required for IE8
            }
        },
        _removeSelectAllItem: function () {
            if (this.selectAllListItem) {
                this.selectAllListItem.remove();
            }
            this.selectAllListItem = null;
        },
        _focus: function (li) {
            if (this.popup.visible() && li && this.trigger(SELECT, { item: li })) {
                this.close();
                return;
            }
            this.select(li);
        },
        //_highlightCurrent: function () {

        //    $('li', this.ul).removeClass(HIGHLIGHTED);
        //    $(this._current).addClass(HIGHLIGHTED);
        //},
        _keydown: function (e) {
            // currently ignore Home and End keys
            // can be added later
            if (e.keyCode == kendo.keys.HOME ||
                e.keyCode == kendo.keys.END) {
                e.preventDefault();
                return;
            }
            DropDownList.fn._keydown.call(this, e);
        },
        _keypress: function(e) {
            // disable existing function
        },
        _move: function (e) {
            var that = this,
                key = e.keyCode,
                ul = that.ul[0],
                down = key === keys.DOWN,
                pressed;
            if (key === keys.UP || down) {
                if (down) {
                    if (!that.popup.visible()) {
                        that.toggle(down);
                    }
                    if (!that._current) {
                        that._current = ul.firstChild;
                    } else {
                        that._current = ($(that._current)[0].nextSibling || that._current);
                    }
                } else {
                    //up
                    // only if anything is highlighted
                    if (that._current) {
                        that._current = ($(that._current)[0].previousSibling || ul.firstChild);
                    }
                }
                if (that._current) {
                    that._scroll(that._current);
                }
                that._highlightCurrent();
                e.preventDefault();
                pressed = true;
            } else {
                pressed = DropDownList.fn._move.call(this, e);
            }
            return pressed;
        },
        selectAll: function () {
            var unselectedItems = this._getUnselectedListItems();
            this._selectItems(unselectedItems);
            // todo: raise custom event
        },
        unselectAll: function () {
            var selectedItems = this._getSelectedListItems();
            this._selectItems(selectedItems);  // will invert the selection
            // todo: raise custom event
        },
        _selectItems: function (listItems) {
            var that = this;
            $.each(listItems, function (i, item) {
                var idx = ui.List.inArray(item, that.ul[0]);
                that.select(idx);  // select OR unselect
            });
        },
        _selectItem: function () {
            // method override to prevent default selection of first item, done by normal dropdown
            var that = this,
                options = that.options,
                useOptionIndex,
                value;
            useOptionIndex = that._isSelect && !that._initial && !options.value && options.index && !that._bound;
            if (!useOptionIndex) {
                value = that._selectedValue || options.value || that._accessor();
            }
            if (value) {
                that.value(value);
            } else if (that._bound === undefined) {
                that.select(options.index);
            }
        },
        _select: function (li) {
            var that = this,
                value,
                text,
                idx;
            li = that._get(li);
            if (li && li[0]) {
                idx = ui.List.inArray(li[0], that.ul[0]);
                if (idx > -1) {
                    if (li.hasClass(SELECTED)) {
                        li.removeClass(SELECTED);
                        that._uncheckItem(li);
                        if (this.selectAllListItem && li[0] === this.selectAllListItem[0]) {
                            this.unselectAll();
                        }
                    } else {
                        li.addClass(SELECTED);
                        that._checkItem(li);
                        if (this.selectAllListItem && li[0] === this.selectAllListItem[0]) {
                            this.selectAll();
                        }
                    }
                    if (this._open) {
                        that._current(li);
                        that._highlightCurrent();
                    }
                    var selecteditems = this._getSelectedListItems();
                    value = [];
                    text = [];
                    $.each(selecteditems, function (indx, item) {
                        var obj = $(item).children("span").first();
                        value.push(obj.attr("data-value"));
                        text.push(obj.text());
                    });
                    that._updateSummary(text);
                    that._updateSelectAllItem();
                    that._accessor(value, idx);
                    // todo: raise change event (add support for selectedIndex) if required
                }
            }

        },
        _getAllValueListItems: function () {
            if (this.selectAllListItem) {
                return this.ul.children("li").not(this.selectAllListItem[0]);
            } else {
                return this.ul.children("li");
            }
        },
        _getSelectedListItems: function () {
            return this._getAllValueListItems().filter("." + SELECTED);
        },
        _getUnselectedListItems: function () {
            return this._getAllValueListItems().filter(":not(." + SELECTED + ")");
        },
        _getSelectedItemsText: function () {
            var text = [];
            var selecteditems = this._getSelectedListItems();
            $.each(selecteditems, function (indx, item) {
                var obj = $(item).children("span").first();
                text.push(obj.text());
            });
            return text;
        },
        _updateSelectAllItem: function () {
            if (!this.selectAllListItem) return;
            // are all items selected?
            if (this._getAllValueListItems().length == this._getSelectedListItems().length) {
                this._checkItem(this.selectAllListItem);
                this.selectAllListItem.addClass(SELECTED);
            }
            else {
                this._uncheckItem(this.selectAllListItem);
                this.selectAllListItem.removeClass(SELECTED);
            }
        },
        _updateSummary: function (itemsText) {
            if (!itemsText) {
                itemsText = this._getSelectedItemsText();
            }
            if (itemsText.length == 0) {
                this._inputWrapper.addClass(EMPTYSELECTION);
                this.text(this.options.emptySelectionLabel);
                return;
            } else {
                this._inputWrapper.removeClass(EMPTYSELECTION);
            }

            if (itemsText.length <= this.options.preSummaryCount) {
                this._textAccessor(itemsText.join(", "));
            }
            else {
                this._textAccessor(itemsText.length + ' selected');
            }
        },
        _checkItem: function (itemContainer) {
            if (!itemContainer) return;
            itemContainer.children("input").prop("checked", true);
        },
        _uncheckItem: function (itemContainer) {
            if (!itemContainer) return;
            itemContainer.children("input").removeAttr("checked");
        },
        _isItemChecked: function (itemContainer) {
            return itemContainer.children("input:checked").length > 0;
        },
        value: function (value) {
            var that = this,
                idx,
                valuesList = [];
            if (value !== undefined) {
                if (!$.isArray(value)) {
                    valuesList.push(value);
                    this._oldValue = valuesList; // to allow for selectionChanged event
                }
                else {
                    valuesList = value;
                    this._oldValue = value; // to allow for selectionChanged event
                }
                // clear all selections first
                $(that.ul[0]).children("li").removeClass(SELECTED);
                $("input", that.ul[0]).removeAttr("checked");
                $.each(valuesList, function (indx, item) {
                    var hasValue;
                    if (item !== null) {
                        item = item.toString();
                    }
                    that._selectedValue = item;
                    hasValue = value || (that.options.optionLabel && !that.element[0].disabled && value === "");
                    if (hasValue && that._fetchItems(value)) {
                        return;
                    }
                    idx = that._index(item);
                    if (idx > -1) {
                        that.select(idx);
                    }
                });
                that._updateSummary();
            }
            else {
                var selecteditems = this._getSelectedListItems();
                return $.map(selecteditems, function(item) {
                    var obj = $(item).children("span").first();
                    return obj.attr("data-value");
                }).join();
            }
        },

    });
    ui.plugin(MultiSelectBox);
})(jQuery);

以下是将小部件添加到我的Kendo列数组中的代码:

/****************************************************************
     * Set up the columns.
     ***************************************************************/
    var columns =  [
        {
            field: 'status',
            title: 'Status',
            width: 80,
            filterable: {
                extra: false, // Don't allow secondary filters.
                operators: {
                    // Sets up filter operators for "string" type columns.
                    string: {
                        // Allow 'equals'.
                        eq: "Equals"
                    }
                },
                ui: function(element) {
                    element.removeAttr("data-bind");
                    element.kendoMultiSelectBox({
                        dataSource: reasonCodes,
                        dataTextField: 'text',
                        dataValueField: 'value',
                        showSelectAll: false,
                        autoBind: false,
                        emptySelectionLabel: "--Select Value(s)--",
                        selectionChanged: function() {
                            applyStatusFilter(this.value());
                        }
                    });
                }
            },
            template: function(dataItem) {
                return dataItem.statusDesc;
            }
        }
    ];

这是我的问题:下拉过滤器仍会显示Kendo&#34;逻辑&#34;选择框#34;等于&#34;,我不想要。我不确定如何隐藏此框而不影响列标题中的所有其他过滤器,因为Kendo没有在其上放置ID。

此外,当用户点击&#34; ---选择值(&#34)时,下拉菜单会阻止过滤器和取消按钮。阻止,这意味着他们必须单击他们的选择,然后单击下拉上方以关闭它,从而再次显示按钮。

最好的情况是我想隐藏逻辑框,仅用于此列,并将提交按钮移动到下拉框上方,以便它们在打开时可见。我还是一个漂亮的绿色javascripter,更不用说使用像剑道这样的图书馆了,其中有很多东西已经完成了#34;自动神奇地#34;所以我一直在挣扎。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:0)

我实际上最终关闭了此列的过滤,使用headerTemplate选项向输入标记添加了ID,并添加了带有JQuery的multiSelectBox:

var statusDropdown = $('#statusMultiSelect');
statusDropdown.kendoMultiSelectBox({
    dataTextField: 'text',
    dataValueField: 'value',
    dataSource: [{"value":"AC","text":"Active"},{"value":"OH","text":"On Hold"},{"value":"CL","text":"Closed"}],
    showSelectAll: false,
    emptySelectionLabel: "Status",
    selectionChanged: function() {
        applyStatusFilter(this.value());
    }
}); 

在我的下拉列表中进行选择时,我只需要根据下拉值手动操作kendo网格过滤器。

答案 1 :(得分:0)

由于未定义的函数_fetchItems,_index和select,您的代码无效。这三个在值中被调用:function(value)。