Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kendo Multi-Select with Checkboxes

I have a problem in implementing the code to the latest kendo version (2016)

Working with 2014 - http://plnkr.co/edit/OVPTCV?p=preview

Issues with 2016 - http://plnkr.co/edit/jmQrngM1oTRoeqhiQIhu?p=preview

//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: true,
            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);  

Now I am unable to check select all. Its not working now and the multi select drop down closes if I select a value.

Please let me know what will be the updates in kendo 2016 version.

like image 463
Ashok Avatar asked Oct 31 '22 06:10

Ashok


1 Answers

Kendo v-2016 has a _get method which I think expects 'li' element from dropdown intead of its index.

So in above multiselect code I replaced _selectItems function with

_selectItems: function (listItems) {
  var that = this;

   $.each(listItems, function (i, item) {
       var idx = ui.List.inArray(item, that.ul[0]);
       var itemToBeSelected = idx !== -1 ? angular.element(item) : idx;
       that.select(itemToBeSelected);  // select OR unselect
   });
}
like image 158
MOHIT KUMAR Avatar answered Nov 13 '22 23:11

MOHIT KUMAR