2
votes

The default behaviour in a multiple Select2 is that the selected option is hidden from .select2-results ul (which can be tweaked via pure css).

.select2-results .select2-selected {
    display: block !important;
    position: relative;
    margin-left: 10px;
}

http://jsfiddle.net/3Vb6d/

However a selected option is not clickable, too. I am looking for a way to toggle an option in the dropdown via a click.

Any and all ideas are highly appreciated. Cheers!

3

3 Answers

1
votes

I guess, I was too quick to seek for help (but it does help to write down the problem sometimes).

1> I had to modify the core select2.js to make a selected option accept at least the hover event, or highlight, as select2.js calls it. Somewhere around the line 1542 there is a method findHighlightableChoices. Instead of looking for these

return this.results.find(".select2-result-selectable:not(.select2-disabled):not(.select2-selected)");

it should not pay attention to already "-selected" classes, so I've made a small change here:

   return this.results.find(".select2-result-selectable:not(.select2-disabled)");//:not(.select2-selected)");

2> Now that all elements, including already selected are clickable, I just catch "select2-selecting" event and see, what it is about. If the same element is being selected - remove it from the array and reset array like this:

            $('.s2').on('select2-selecting', function(e){
            existingVals = $(this).val();
            if (!existingVals || existingVals.length == 0) return;
            for (a = 0; a<existingVals.length; a++) {
                if (existingVals[a] == e.val) {
                    e.preventDefault();
                    existingVals[a] = '';
                    $(this).val(existingVals).trigger('change');
                }
            }
        });

And that's it!

Select2 is just one great plugin.

1
votes

Don't edit select2.js. Just use this in your js:

Select2.class.multi.prototype.findHighlightableChoices = function () {
    return this.results.find(".select2-result-selectable:not(.select2-disabled)");
};

var Select2TriggerSelect = Select2.class.multi.prototype.triggerSelect;

Select2.class.multi.prototype.triggerSelect = function (data) {
    if (this.val().indexOf(this.id(data)) !== -1) {

        var val = this.id(data);
        var evt = $.Event("select2-removing");
        evt.val = val;
        evt.choice = data;
        this.opts.element.trigger(evt);

        if (evt.isDefaultPrevented()) {
            return false;
        }

        var existingVals = this.val();
        var self = this;
        if (!existingVals || existingVals.length == 0) return true;
        for (a = 0; a < existingVals.length; a++) {
            if (existingVals[a] === val) {
                existingVals[a] = '';
                this.val(existingVals);
                this.results.find('.select2-result').each(function () {
                    var $this = $(this);
                    if (self.id($this.data('select2-data')) === val) {
                        $this.removeClass('select2-selected');
                    }
                });
            }
        }

        this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data });
        this.triggerChange({ removed: data });

    } else {
        return Select2TriggerSelect.apply(this, arguments);
    }
}
0
votes

I wasn't able to get any of these solutions to work the way I wanted, so I wrote my own implementation of a toggle-able item in Select2. Features include:

  • display Primary selected item on a separate Form line
  • submit Primary selected item choice in a hidden form field
  • automatically set first selected item as Primary
  • highlight Primary selected item with green gradient
  • does not modify Select2 source
  • supports any normal Select2 options
  • supports destroy interface for dynamic form fields
  • use .select2-primary class on an option to default it to Primary

It is attaching a click and a change handler and calling a function selectPrimary that does the work

s2Instance.container.on('click.s2p','.select2-search-choice', function(e) {
    selectPrimary($(this));
});
$element.on('change.s2p', function(e) {
    if (e.added && s2Instance.val().length === 1) {
        // if it's the first one added, set it as Primary automatically
        selectPrimary();
    } else {
        // auto detect what should be primary in other cases
        selectPrimary(null, true);
    }
});

Full code is here: http://jsfiddle.net/HugeHugh/o5veephv/

I wrote this blog post to explain the solution in detail.