Selecting multiple from an html select element without using ctrl key

I've come across various solutions to this issue on the net.

Basically, I find having to hold down ctrl a bit cheesy, and I want the select list to just select whatever I click on and add it to the currently selected items.

I've already got this code:

    $("select[multiple] option").mousedown(function () {
        var $self = $(this);            

        if ($self.attr("selected")) {                
            $self.removeAttr("selected", "");
        }
        else {
            $self.attr("selected", "selected");
        }

        return false;            
    });

Element:

    <select multiple id="WOStatusKey" name="WOStatusKey">                
        <option value="1">Created</option>
        <option value="2">In Process</option>
        <!-- etc. (about 20 of these) -->
    </select>

It works fine with one exception: any time something is selected/deselected that is not at the top of the list (where you have to scroll to see it) then it pops back up to the top after you select it. I've played around with it a little bit but can't figure out anything to prevent this behavior. Also, I've seen a couple other solutions to this problem, although nothing that either works or works well.

I only need this to work in Chrome. Also, I am not interested in any alternative solutions to using a select list.

Thank you for any help, it is much appreciated.

Answers:

Answer

You can save the Element.scrollTop and set it at the end.

$("select").mousedown(function(e){
    e.preventDefault();

    var select = this;
    var scroll = select .scrollTop;

    e.target.selected = !e.target.selected;

    setTimeout(function(){select.scrollTop = scroll;}, 0);

    $(select ).focus();
}).mousemove(function(e){e.preventDefault()});

http://jsfiddle.net/UziTech/cjjg68dr/114/

Answer

Here is a pure JS solution:

element.onmousedown= function(event) {
    //this == event.target
    event.preventDefault();
    var scroll_offset= this.parentElement.scrollTop;
    this.selected= !this.selected;
    this.parentElement.scrollTop= scroll_offset;
}
element.onmousemove= function(event) {
    event.preventDefault();
}

Look at the parent element(the select box) and record the vertical scroll offset before selecting/deselecting the option. Then reset it manually once you have performed the action.

The reasoning behind preventing default behavior for the mousemove event is because if you don't prevent it and you happen to click an option while moving the mouse, all options will become de-selected.

Answer

Tony's answer makes the select arrows buggy, as they work only if you hold the mouse down.

I've combined a few solutions into this, and it works fine at least in Chrome and FF:

// multiple select: selectable without Control
$('select[multiple] option').on('mousedown', function(e) {
    var $this = $(this),
        that = this,
        scroll = that.parentElement.scrollTop;

    e.preventDefault();
    $this.prop('selected', !$this.prop('selected'));

    setTimeout(function() {
        that.parentElement.scrollTop = scroll;
    }, 0);

    return false;
});
Answer

Here's a solution that appears to work in Chrome FF and IE. It's not terribly pretty because it flashes a little bit when clicking.

var vals = [];
$("select[multiple]").click(function(e){
        var scroll_offset= this.scrollTop;
      var newVals = $(this).val();
    if (newVals.length === 1) {
        var index = vals.indexOf(newVals[0])
        if (index > -1) {
        vals.splice(index, 1);
      } else {
        vals.push(newVals[0])
      }
      $(this).val(vals);
      this.scrollTop = scroll_offset;
    }
});

jsfiddle

Answer

For a pure js solution in chrome set the event listener on "onmouseup" instead. The event that resets the scroll to the first element is fired on the mouse up. So for example:

element.onmouseup = function(event) {
    event.preventDefault();
    var st = this.scrollTop;
    setTimeout(function () { element.scrollTop = st; }, 0);
};
Answer

This worked better for me than the other suggestions, because it is vanilla JS and it behaves more similarly to the original still, for example allows quick selection of many items via the shift key.

element.onmousedown = function(event) {
    if (event.shiftKey) return;
    event.preventDefault();
    this.focus();
    var scroll = this.scrollTop;
    event.target.selected = !event.target.selected;
    this.scrollTop = scroll;
    // make sure that other listeners (like Vue) pick up on the change
    // even though we prevented the default.
    this.dispatchEvent(new Event("change"));
}

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.