I have a form with multiple text inputs and some select2 elements. Using the keyboard to tab between fields works fine - the Select2 element behaves like a form element and receives focus when tabbing. I was wondering if it is possible to open the dropdown when the Select2 element gets focus.
Here's what I've tried so far:
$("#myid").select2().on('select2-focus', function(){
$(this).select2('open');
});
But using this code makes the dropdown to open again after a selection is made.
This question is related to
javascript
jquery
jquery-select2
jquery-select2-4
an important thing is to keep the multiselect open all the time. The simplest way is to fire open event on 'conditions' in your code:
<select data-placeholder="Choose a Country..." multiple class="select2-select" id="myList">
<option value="United States">United States</option>
<option value="United Kingdom">United Kingdom</option>
<option value="Afghanistan">Afghanistan</option>
<option value="Aland Islands">Aland Islands</option>
<option value="Albania">Albania</option>
<option value="Algeria">Algeria</option>
</select>
javascript:
$(".select2-select").select2({closeOnSelect:false});
$("#myList").select2("open");
a bit late... but to share my code using select2 4.0.0
$("#my_id").select2();
$("#my_id").next(".select2").find(".select2-selection").focus(function() {
$("#my_id").select2("open");
});
Here is an alternate solution for version 4.x of Select2. You can use listeners to catch the focus event and then open the select.
$('#test').select2({
// Initialisation here
}).data('select2').listeners['*'].push(function(name, target) {
if(name == 'focus') {
$(this.$element).select2("open");
}
});
Find the working example here based the exampel created by @tonywchen
For me using Select2.full.js Version 4.0.3 none of the above solutions was working the way it should be. So I wrote a combination of the solutions above. First of all I modified Select2.full.js to transfer the internal focus and blur events to jquery events as "Thomas Molnar" did in his answer.
EventRelay.prototype.bind = function (decorated, container, $container) {
var self = this;
var relayEvents = [
'open', 'opening',
'close', 'closing',
'select', 'selecting',
'unselect', 'unselecting',
'focus', 'blur'
];
And then I added the following code to handle focus and blur and focussing the next element
$("#myId").select2( ... ).one("select2:focus", select2Focus).on("select2:blur", function ()
{
var select2 = $(this).data('select2');
if (select2.isOpen() == false)
{
$(this).one("select2:focus", select2Focus);
}
}).on("select2:close", function ()
{
setTimeout(function ()
{
// Find the next element and set focus on it.
$(":focus").closest("tr").next("tr").find("select:visible,input:visible").focus();
}, 0);
});
function select2Focus()
{
var select2 = $(this).data('select2');
setTimeout(function() {
if (!select2.isOpen()) {
select2.open();
}
}, 0);
}
Probably after the selection is made a select2-focus
event is triggered.
The only way I found is a combination of select2-focus
and select2-blur
event and the jQuery one
event handler.
So the first time the element get the focus, the select2 is opened for one time (because of one), when the element is blurred the one event handler is attached again and so on.
Code:
$('#test').select2({
data: [{
id: 0,
text: "enhancement"
}, {
id: 1,
text: "bug"
}, {
id: 2,
text: "duplicate"
}, {
id: 3,
text: "invalid"
}, {
id: 4,
text: "wontfix"
}],
width: "300px"
}).one('select2-focus', select2Focus).on("select2-blur", function () {
$(this).one('select2-focus', select2Focus)
})
function select2Focus() {
$(this).select2('open');
}
Demo: http://jsfiddle.net/IrvinDominin/fnjNb/
To let the mouse click work you must check the event that fires the handler, it must fire the open
method only if the event is focus
Code:
function select2Focus() {
if (/^focus/.test(event.type)) {
$(this).select2('open');
}
}
Demo: http://jsfiddle.net/IrvinDominin/fnjNb/4/
select2 v 4.0 has changed its API's and dropped the custom events (see https://github.com/select2/select2/issues/1908). So it's necessary change the way to detect the focus on it.
Code:
$('.js-select').select2({
placeholder: "Select",
width: "100%"
})
$('.js-select').next('.select2').find('.select2-selection').one('focus', select2Focus).on('blur', function () {
$(this).one('focus', select2Focus)
})
function select2Focus() {
$(this).closest('.select2').prev('select').select2('open');
}
Somehow select2Focus didn't work here with empty selection, couldn't figured out the issue, therefore I added manual control when after focus event auto open get's triggered.
Here is coffeescript:
$("#myid").select2()
.on 'select2-blur', ->
$(this).data('select2-auto-open', 'true')
.on 'select2-focus', ->
$(this).data('select2').open() if $(this).data('select2-auto-open') != 'false'
.on 'select2-selecting', ->
$(this).data('select2-auto-open', 'false')
I've tried a pretty ugly solution but it fixed my problem.
var tabPressed = false;
$(document).keydown(function (e) {
// Listening tab button.
if (e.which == 9) {
tabPressed = true;
}
});
$(document).on('focus', '.select2', function() {
if (tabPressed) {
tabPressed = false;
$(this).siblings('select').select2('open');
}
});
The current answer is only applicable to versions 3.5.4 and before, where select2 fired blur and focus events (select2-focus
& select2-blur
). It attaches a one-time use handler using $.one
to catch the initial focus, and then reattaches it during blur for subsequent uses.
$('.select2').select2({})
.one('select2-focus', OpenSelect2)
.on("select2-blur", function (e) {
$(this).one('select2-focus', OpenSelect2)
})
function OpenSelect2() {
var $select2 = $(this).data('select2');
setTimeout(function() {
if (!$select2.opened()) { $select2.open(); }
}, 0);
}
I tried both of @irvin-dominin-aka-edward's answers, but also ran into both problems (having to click the dropdown twice, and that Firefox throws 'event is not defined').
I did find a solution that seems to solve the two problems and haven't run into other issue yet. This is based on @irvin-dominin-aka-edward's answers by modifying the select2Focus function so that instead of executing the rest of the code right away, wrap it in setTimeout.
$('.select2').select2({})_x000D_
.one('select2-focus', OpenSelect2)_x000D_
.on("select2-blur", function (e) {_x000D_
$(this).one('select2-focus', OpenSelect2)_x000D_
})_x000D_
_x000D_
function OpenSelect2() {_x000D_
var $select2 = $(this).data('select2');_x000D_
setTimeout(function() {_x000D_
if (!$select2.opened()) { $select2.open(); }_x000D_
}, 0); _x000D_
}
_x000D_
body {_x000D_
margin: 2em;_x000D_
}_x000D_
_x000D_
.form-control {_x000D_
width: 200px; _x000D_
margin-bottom: 1em;_x000D_
padding: 5px;_x000D_
display: flex;_x000D_
flex-direction: column;_x000D_
}_x000D_
_x000D_
select {_x000D_
border: 1px solid #aaa;_x000D_
border-radius: 4px;_x000D_
height: 28px;_x000D_
}
_x000D_
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.4/select2.css">_x000D_
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>_x000D_
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.4/select2.js"></script>_x000D_
_x000D_
_x000D_
<div class="form-control">_x000D_
<label for="foods1" >Normal</label>_x000D_
<select id="foods1" >_x000D_
<option value=""></option>_x000D_
<option value="1">Apple</option>_x000D_
<option value="2">Banana</option>_x000D_
<option value="3">Carrot</option>_x000D_
<option value="4">Donut</option>_x000D_
</select>_x000D_
</div>_x000D_
_x000D_
<div class="form-control">_x000D_
<label for="foods2" >Select2</label>_x000D_
<select id="foods2" class="select2" >_x000D_
<option value=""></option>_x000D_
<option value="1">Apple</option>_x000D_
<option value="2">Banana</option>_x000D_
<option value="3">Carrot</option>_x000D_
<option value="4">Donut</option>_x000D_
</select>_x000D_
</div>
_x000D_
KyleMit's answer worked for me (thank you!), but I noticed that with select2 elements that allow for searching, trying to tab to the next element wouldn't work (tab order was effectively lost), so I added code to set focus back to the main select2 element when the dropdown is closing:
$(document).on('focus', '.select2', function (e) {
if (e.originalEvent) {
var s2element = $(this).siblings('select');
s2element.select2('open');
// Set focus back to select2 element on closing.
s2element.on('select2:closing', function (e) {
s2element.select2('focus');
});
}
});
The problem is, that the internal focus event is not transformed to jQuery event, so I've modified the plugin and added the focus event to the EventRelay on line 2063 of Select2 4.0.3:
EventRelay.prototype.bind = function (decorated, container, $container) {
var self = this;
var relayEvents = [
'open', 'opening',
'close', 'closing',
'select', 'selecting',
'unselect', 'unselecting',
'focus'
]};
Then it is enough to open the select2 when the focus occurs:
$('#select2').on('select2:focus', function(evt){
$(this).select2('open');
});
Works well on Chrome 54, IE 11, FF 49, Opera 40
I've had the problem which was two pronged:
1. In a form with multiple select2 elements, the dropdown won't open on tab, and you need to press space key to open it
2. Once you have made a selection, the tabindex won't be honored and you have to manually click on the next input field
While the usual suggestions worked, I came up with my own version, since a library script was doing the conversion of normal select to select2, and hence I had no control over this initialization.
Here is the code that worked for me.
Tab to open
$(document).on("focus", ".select2", function() {
$(this).siblings("select").select2("open");
});
Move to next on selection
var inputs = $("input,select"); // You can use other elements such as textarea, button etc.
//depending on input field types you have used
$("select").on("select2:close",function(){
var pos = $(inputs).index(this) + 1;
var next = $(inputs).eq(pos);
setTimeout( function() {
next.focus();
if (next.siblings(".select2").length) { //If it's a select
next.select2("open");
}
}, 500); //The delay is required to allow default events to occur
});
Hope this helps.
Something easy that would work on all select2 instances on the page.
$(document).on('focus', '.select2', function() {
$(this).siblings('select').select2('open');
});
UPDATE: The above code doesn't seem to work properly on IE11/Select2 4.0.3
PS: also added filter to select only single
select fields. Select with multiple
attribute doesn't need it and would probably break if applied.
var select2_open;
// open select2 dropdown on focus
$(document).on('focus', '.select2-selection--single', function(e) {
select2_open = $(this).parent().parent().siblings('select');
select2_open.select2('open');
});
// fix for ie11
if (/rv:11.0/i.test(navigator.userAgent)) {
$(document).on('blur', '.select2-search__field', function (e) {
select2_open.select2('close');
});
}
This worked for me using Select2 v4.0.3
//Initialize Select2
jQuery('.js-select').select2();
// Make Select2 respect tab focus
function select2Focus(){
jQuery(window).keyup(function (e) {
var code = (e.keyCode ? e.keyCode : e.which);
if (code == 9 && jQuery('.select2-search__field:focus').length) {
jQuery('.js-select').select2('open');
}
});
}
select2Focus();
Fork of Irvin Dominin's demo: http://jsfiddle.net/163cwdrw/
I tried a number of these and finally came up with the following that works for me with Select2 4.0.1. element is the <select>
element.
$.data(element).select2.on("focus", function (e) {
$(element).select2("open");
});
I tried these solutions with the select2 version 3.4.8 and found that when you do blur
, the select2 triggers first select2-close
then select2-focus
and then select2-blur
, so at the end we end up reopening forever the select2.
Then, my solution is this one:
$('#elemId').on('select2-focus', function(){
var select2 = $(this).data('select2');
if( $(this).data('select2-closed') ){
$(this).data('select2-closed', false)
return
}
if (!select2.opened()) {
select2.open()
}
}).on('select2-close', function(){
$(this).data('select2-closed', true)
})
Source: Stackoverflow.com