multiple select box only selects multiple values on ctrl click [duplicate] - javascript

I thought this would be a simple hack, but I've now been searching for hours and can't seen to find the right search term. I want to have an ordinary multiple select box (<select multiple="multiple">) except I don't want the user to have to hold down the control key to make multiple selections.
In other words, I want a left click to toggle the <option> element that's under the cursor without changing any of the others. In other other words, I want something that looks like a combo list box but behaves like a group of check boxes.
Can anybody suggest a simple way to do this in Javascript? Thanks.

Check this fiddle: http://jsfiddle.net/xQqbR/1022/
You basically need to override the mousedown event for each <option> and toggle the selected property there.
$('option').mousedown(function(e) {
e.preventDefault();
$(this).prop('selected', !$(this).prop('selected'));
return false;
});
For simplicity, I've given 'option' as the selector above. You can fine tune it to match <option>s under specific <select> element(s). For ex: $('#mymultiselect option')

Had to solve this problem myself and noticed the bugged behavior a simple interception of the mousedown and setting the attribute would have, so made a override of the select element and it works good.
jsFiddle: http://jsfiddle.net/51p7ocLw/
Note: This code does fix buggy behavior by replacing the select element in the DOM. This is a bit agressive and will break event handlers you might have attached to the element.
window.onmousedown = function (e) {
var el = e.target;
if (el.tagName.toLowerCase() == 'option' && el.parentNode.hasAttribute('multiple')) {
e.preventDefault();
// toggle selection
if (el.hasAttribute('selected')) el.removeAttribute('selected');
else el.setAttribute('selected', '');
// hack to correct buggy behavior
var select = el.parentNode.cloneNode(true);
el.parentNode.parentNode.replaceChild(select, el.parentNode);
}
}
<h4>From</h4>
<div>
<select name="sites-list" size="7" multiple>
<option value="site-1">SITE</option>
<option value="site-2" selected>SITE</option>
<option value="site-3">SITE</option>
<option value="site-4">SITE</option>
<option value="site-5">SITE</option>
<option value="site-6" selected>SITE</option>
<option value="site-7">SITE</option>
<option value="site-8">SITE</option>
<option value="site-9">SITE</option>
</select>
</div>

techfoobar's answer is buggy, it unselects all options if you drag the mouse.
Sergio's answer is interesting, but cloning and removing events-bound to a dropdown is not a nice thing.
Try this answer.
Note: Doesn't work on Firefox, but works perfectly on Safari/Chrome/Opera. (I didn't test it on IE)
EDIT (2020)
After 5 years since my original answer, I think best practice here is to replace the dropdown with checkboxes. Think about it, that's the main reason why checkboxes exist in the first place, and it works nicely with old browsers like IE & modern mobiles without any custom JS to handle all the wacky scenarios.

Necromancing.
The selected answer without jQuery.
Also, it missed setting the focus when an option is clicked, because you have to do this yourself, if you write e.preventDefault...
Forgetting to do focus would affect CSS-styling, e.g. bootstrap, etc.
var options = [].slice.call(document.querySelectorAll("option"));
options.forEach(function (element)
{
// console.log("element", element);
element.addEventListener("mousedown",
function (e)
{
e.preventDefault();
element.parentElement.focus();
this.selected = !this.selected;
return false;
}
, false
);
});

I had same problem today, generally the advice is to use a list of hidden checkboxes and emulate the behavior via css, in this way is more easy to manage but in my case i don't want to modify html.
At the moment i've tested this code only with google chrome, i don't know if works with other browser but it should:
var changed;
$('select[multiple="multiple"]').change(function(e) {
var select = $(this);
var list = select.data('prevstate');
var val = select.val();
if (list == null) {
list = val;
} else if (val.length == 1) {
val = val.pop();
var pos = list.indexOf(val);
if (pos == -1)
list.push(val);
else
list.splice(pos, 1);
} else {
list = val;
}
select.val(list);
select.data('prevstate', list);
changed = true;
}).find('option').click(function() {
if (!changed){
$(this).parent().change();
}
changed = false;
});
Of course suggestions are welcome but I have not found another way

Related

Jquery Click select box option not work on Chrome [duplicate]

I'm having a problem in Chrome with the following:
var items = $("option", obj);
items.each(function(){
$(this).click(function(){
// alert("test");
process($(this).html());
return false;
});
});
The click event doesn't seem to fire in Chrome, but works in Firefox.
I wanna be able to click on a option element from a combo, if I do instead another kind of element, lets say <li> it works fine. Any ideas? Thanks.
I don't believe the click event is valid on options. It is valid, however, on select elements. Give this a try:
$("select#yourSelect").change(function(){
process($(this).children(":selected").html());
});
We can achieve this other way despite of directly calling event with <select>.
JS part:
$("#sort").change(function(){
alert('Selected value: ' + $(this).val());
});
HTML part:
<select id="sort">
<option value="1">View All</option>
<option value="2">Ready for Review</option>
<option value="3">Registration Date</option>
<option value="4">Last Modified</option>
<option value="5">Ranking</option>
<option value="6">Reviewed</option>
</select>
The easy way to change the select, and update it is this.
// BY id
$('#select_element_selector').val('value').change();
another example:
//By tag
$('[name=selectxD]').val('value').change();
another example:
$("#select_element_selector").val('value').trigger('chosen:updated');
I've had simmilar issue. change event was not good for me because i've needed to refresh some data when user clicks on option. After few trials i've got this solution:
$('select').on('click',function(ev){
if(ev.offsetY < 0){
//user click on option
}else{
//dropdown is shown
}
});
I agree that this is very ugly and you should stick with change event where you can, but this solved my problem.
I found that the following worked for me - instead on using on click, use on change e.g.:
jQuery('#element select').on('change', (function() {
//your code here
}));
<select id="myselect">
<option value="0">sometext</option>
<option value="2">Ready for Review</option>
<option value="3">Registration Date</option>
</select>
$('#myselect').change(function() {
if($('#myselect option:selected').val() == 0) {
...
}
else {
...
}
});
Looking for this on 2018.
Click event on option tag, inside a select tag, is not fired on Chrome.
Use change event, and capture the selected option:
$(document).delegate("select", "change", function() {
//capture the option
var $target = $("option:selected",$(this));
});
Be aware that $target may be a collection of objects if the select tag is multiple.
I use a two part solution
Part 1 - Register my click events on the options like I usually would
Part 2 - Detect that the selected item changed, and call the click
handler of the new selected item.
HTML
<select id="sneaky-select">
<option id="select-item-1">Hello</option>
<option id="select-item-2">World</option>
</select>
JS
$("#select-item-1").click(function () { alert('hello') });
$("#select-item-2").click(function () { alert('world') });
$("#sneaky-select").change(function ()
{
$("#sneaky-select option:selected").click();
});
What usually works for me is to first change the value of the dropdown, e.g.
$('#selectorForOption').attr('selected','selected')
and then trigger the a change
$('#selectorForOption').changed()
This way, any javascript that is wired to
Maybe one of the new jquery versions supports the click event on options. It worked for me:
$(document).on("click","select option",function() {
console.log("nice to meet you, console ;-)");
});
UPDATE: A possible usecase could be the following: A user sends a html form and the values are inserted into a database. However one or more values are set by default and you flag this automated entries. You also show the user that his entry is generated automatically, but if he confirm the entry by clicking on the already selected option you change the flag in the database. A rare sue case, but possible...
I know that this code snippet works for recognizing an option click (at least in Chrome and FF). Furthermore, it works if the element wasn't there on DOM load. I usually use this when I input sections of inputs into a single select element and I don't want the section title to be clicked.
$(document).on('click', 'option[value="disableme"]', function(){
$('option[value="disableme"]').prop("selected", false);
});
Since $(this) isn't correct anymore with ES6 arrow function which don't have have the same this than function() {}, you shouldn't use $( this ) if you use ES6 syntax.
Besides according to the official jQuery's anwser, there's a simpler way to do that what the top answer says.
The best way to get the html of a selected option is to use
$('#yourSelect option:selected').html();
You can replace html() by text() or anything else you want (but html() was in the original question).
Just add the event listener change, with the jQuery's shorthand method change(), to trigger your code when the selected option change.
$ ('#yourSelect' ).change(() => {
process($('#yourSelect option:selected').html());
});
If you just want to know the value of the option:selected (the option that the user has chosen) you can just use $('#yourSelect').val()
Workaround:
$('#select_id').on('change', (function() {
$(this).children(':selected').trigger('click');
}));

How to run a function by clicking an option in a drop down select tag?

I have a drop down select tag like so :
<select id="thisDropDown" onChange="doSomething()">
<option></option>
<option>classif</option>
<option>status</option>
</select>
Notice I'm using the onChange();
What I need is the ability to re-click an option in my drop down so it runs the function again (as I can change other drop downs which affect the outcome of running this function).
I have tried onselect() and onclick() but none seem to work. Do I have to write a bit of script ? I have been looking online but can't seem to find something that will work.
Thanks in advance, sorry if something similar has been asked before
We can achieve this but with minor tweaks which are required based on the browser
JSFiddle link https://jsfiddle.net/0kxe6br7/2/
var dom = "select#thisDropDown";
var is_firefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
if(is_firefox){
dom+=" option";
}
$(dom).on("click",function(event) {
console.log($(event.currentTarget).val());
});
Hej,
This can be done with jquery
$('#thisDropDown').on('mouseup', function() {
alert('select option');
});

Hacking select multiple in javascript, flicke

I've hacked html's < select multiple > with javascript, according to my customer's specifications:
clicking an item only toggles that item's selected status.
other selected items stay selected.
The little bit of javascript remembers all selected values.
When the user clicks, only the option he clicks will be selected.
The javascript selects the options he remembers.
However, it causes a flicker effect. I doubt there is any solution for this, but I felt I had to ask just in case, does anyone know of a way to delay the rendering, or any other solution to accomplish this, without a flicker?
Best regards.
EDIT: here is the code
var choices=new Array();
function prepmulti(){
var m=document.querySelectorAll('select');
for(var i=0;i<m.length;i++)
if(m[i].id!=''){
m[i].onclick=toggle;
choices.push(new Array());
}
}
function toggle(){
var sel, x;
for(var i=0; i<this.options.length;i++)
if(this.options[i].selected){
sel=i;
break;
}
if((x=choices[this.id].indexOf(sel))<0)
choices[this.id].push(sel);
else{
choices[this.id].splice(x, 1);
this.options[sel].selected=false;
}
for(i=0;i<choices[this.id].length;i++)
this.options[choices[this.id][i]].selected=true;
}
<body onload='prepmulti();'>
The select multiples have ids 0, 1, 2, etc... If you give them other ids, the code must be modified a little.
The flicker you see is from it changing the selected option(s) then repainting - unfortunately I don't think this is avoidable in most browsers.
In Chrome you can bind onmousedown on the select, use preventDefault and then set the event target's selected to the opposite of what it is.
var m=document.querySelectorAll('select');
for(var i=0;i<m.length;i++)
{
m[i].onmousedown = function(e) {
e.preventDefault();
e.target.selected = !e.target.selected;
};
}
http://jsfiddle.net/VDnQK/
This only works in Chrome, though. IE supports preventDefault for select but e.target returns the select rather than the option element.
FireFox doesn't seem to support preventDefault for select (at least, I can't get it to work).

select onchange same value

Is there a way to trigger an event if I open a dropdown select, and select the same value WITHOUT clicking away to switch focus?
I tried
onblur, but it only works if I make an extra click outside the select.
onchange, but it only works if I select a different value.
I need to trigger an event simply if I open the dropdown and select anything, regardless of whether it is the same or different.
<select name='show1' id='show1' onblur='dosomething(this);'>
<option value='1'>One</option>
<option value='2'>Two</option>
</select>
I think you'd have to use the onClick-event and store the previously selected item in a variable.
Here's a quick example which I think could use some refactoring :-)
var dropboxOpen = false,
oldItem = null;
function onClick(e) {
if (dropboxOpen) {
if (oldItem && oldItem === e.target.value) {
console.log('same selected');
}
oldItem = e.target.value;
}
dropboxOpen = !dropboxOpen;
}
http://jsfiddle.net/vtHPV/
It doesn't matter what library or framework you use, but this is quite simple. You are essentially looking for two things to be true:
Test that the control was clicked.
Test that a value (any value) has been selected, --or-- is still selected.
Number 2 can be achieved with something like...
var elem = document.getElementById("ddlViewBy");
var value = elem.options[elem.selectedIndex].value;
It's then a simple matter to test that it is non-empty.
If you use jQuery
You can try focus() event.

Selecting and Deselecting multiple options from list without keyboard

I have the following list that is present to the user
<select id="regions" multiple="multiple">
<option value='us-west' selected="selected">US West Coast</option>
<option value='us-east' selected="selected">US East Coast</option>
<option value='eur' selected="selected">Europe</option>
<option value='asia' selected="selected">Asia</option>
</select>
As shown above, all items are selected.
I was trying to implement a jquery function where if the user clicks an option on the list only the clicked item (let's say Europe) will be removed, while the rest of the options are selected. I know that this is possible by holding down "CTRL" and clicking, but is there a way where all the user has to do is to click?
I tried this function:
<script type="text/javascript">
function(){
$("#regions options:selected").removeAttr("selected");
};
</script>
So it took me a while, but I think I have the functionality you're looking for.
Check this fiddle
The idea is, create an array to keep track of what's selected. The natural behaviour of a multiple select box if you only click, is to deselect all other selections and select what you clicked on.
Therefore, instead of being concerned with what's in the selectbox, we see which option is clicked on (on mousedown) and add it to our personal list of what's selected, then update the select box to reflect whats in our list (on mouseup).
This prevents the user from dragging to select multiple items in the selectbox, but being able to do that would probably just mess it up.
var selection = [];
$('#the_box > option').mousedown(function(){
if(selection.length < 1){
selection.push($(this).val());
} else {
var found = 0;
for(i = 0; i < selection.length; i++) {
if(selection[i] == $(this).val()){
selection.splice(i, 1);
found = 1;
break;
}
}
if(found === 0){
selection.push($(this).val());
}
}
});
$('#the_box').bind('mouseup mouseout', function(){
$(this).children('option').each(function(){
$(this).removeAttr('selected');
});
$(this).children('option').each(function(){
for(i = 0; i < selection.length; i++){
if($(this).val() == selection[i]){
$(this).attr('selected','selected');
}
}
});
});
You would however, be able to do this exact thing with just a list or set of divs, instead of using the native <select> tags, which would actually be easier if you're using this method (due to not having to work around the default behavior of the selectbox) :P
You can use:
$('option').click(function(){
$(this).removeAttr('selected', 'selected')
.siblings().attr('selected', 'selected');
});
What this function does, is to remove current selection state of the clicked item, but re-selecting the entire siblings set.
See this fiddle.
Update: Since by using keyboard, we can send another signal (another flag) to the control, we still need to simulate it somehow using mouse. We can for example assume that right-click is like Ctrl+click and left click is simply a click. However, right-click is not a good pattern in web and not that common.
Another option could be to redefine our business to make the control behave differently (for example, on mouse click, if the object is already selected, then deselect it, and if it's not selected, add it to the whole collection of selected options). But the disadvantage of this approach is that users get lost when using your control, because it gets far from normal HTML controls with which they have interaction on a daily basis. In other words, changing the behavior of a control is not a good solution regarding UX.
This is by no means the perfect solution but you are welcome to try it.
To attach the function (note that this allows a callback function to be fired after selecting items .. for example if you want to populate another list based on the selection)
$('#mySelect').click(function () {
singleClickList(this, myCallbackFunction);
});
The function:
function singleClickList(mythis, callback) {
var selected = $(mythis).data('selected');
if (selected == undefined) selected = [];
var scrollTop = mythis.scrollTop;
var current = $(mythis).val();
var index;
if (current != null) {
if (current.length > 0) {
index = $.inArray(current[0], selected);
if (index >= 0)
selected.splice(index, 1);
else
selected.push(current[0]);
}
$(mythis).val(selected);
$(mythis).data('selected', selected);
mythis.scrollTop = scrollTop;
if (callback) callback();
}
}
Note that this requires jquery, and makes use of the jquery .data method to store the array of selected items.

Categories