Open philipstratford opened 9 years ago
I agree, this appears to be a breaking Ux change in 4.0. I would also include the change in behavior to the clear button (x) as a breaking Ux change in 4.0. It now displays the drop down automatically when clearing the selection. Any suggestions on work-around(s) for these issues ?
This was an intentional change, and in order to understand why we changed it you need to understand how it was done before.
We started off doing this by listening to key events when the <div>
was focused, and then repeating the character into the text box. This had two unfortunate side effects:
So we decided to make the focusing element an <input />
box, and have it be hidden out of sight. This fixed the IE issues, and we could consistently get the character typed (just get the .value
). Eventually we were able to alleviate the second issue, but we ended up adding in a few new side effects:
<input />
was actually for. And some screen readers actually ignored it, so it was impossible to navigate Select2 through a keyboard.And that's why we added a shouldFocusInput
option in Select2 3.x that disables the automatic focusing of the input if the user is on a mobile device and there isn't a visible search box. While that worked in a way, it was never considered anything more than a hack.
And that's why we no longer try to handle that case magically in Select2 4.0.
If we took the easy route and automatically opened the dropdown when we detected a keypress, that would work some of the time. But we would run into exactly the same issue that we originally hit. It would also block any possibility of us getting the searching to work when the dropdown is not open (so you can quickly select things), which is far out on our roadmap.
So we made the decision to not support it in Select2 4.0. You can still open the dropdown by hitting [space] or [enter], which is how it works in a normal <select>
.
Thanks for the details. Ed
On Sun, Apr 26, 2015 at 5:01 PM, Kevin Brown notifications@github.com wrote:
This was an intentional change, and in order to understand why we changed it you need to understand how it was done before.
We started off doing this by listening to key events when the
was focused, and then repeating the character into the text box. This had two unfortunate side effects:
- Not all browsers (cough Internet Explorer) handled key events the same way, and it was difficult to consistently get the typed in character.
- Moving that typed character over to the search box meant moving the keyboard focus over and ensuring that the character wasn't highlighted. This proved to be more difficult than it should have, and both IE and Firefox had a tendency to lose the first character.
So we decided to make the focusing element an box, and have it be hidden out of sight. This fixed the IE issues, and we could consistently get the character typed (just get the .value). Eventually we were able to alleviate the second issue, but we ended up adding in a few new side effects:
- Because were were automatically focusing the keyboard, any interaction with Select2 on a mobile device would trigger the on-screen keyboard.
- We created an accessibility problem because there was no indication of what the focusing was actually for. And some screen readers actually ignored it, so it was impossible to navigate Select2 through a keyboard.
And that's why we added a shouldFocusInput option in Select2 3.x that disables the automatic focusing of the input if the user is on a mobile device and there isn't a visible search box. While that worked in a way, it was never considered anything more than a hack.
And that's why we no longer try to handle that case magically in Select2 4.0.
If we took the easy route and automatically opened the dropdown when we detected a keypress, that would work some of the time. But we would run into exactly the same issue that we originally hit. It would also block any possibility of us getting the searching to work when the dropdown is not open (so you can quickly select things), which is far out on our roadmap.
So we made the decision to not support it in Select2 4.0. You can still open the dropdown by hitting [space] or [enter], which is how it works in a normal
— Reply to this email directly or view it on GitHub https://github.com/select2/select2/issues/3279#issuecomment-96450069.
I can partially understand this reasoning for the regular select, but for the multiselect it's a pretty bad user experience. The multiselect looks visually like a regular input, and when you tab to it, it's not at all clear that you're dealing with a mutliselect, so when there's no cursor it's quite confusing and pressing the spacebar is not intuitive.
I agree with @philipwalton. The select looks like an string input and should therefore act in a similar way. If it's confusing developers using it, chances are it's also going to their users too. With that said, I can understand it's a difficult issue, but that just doesn't make it resolved just by stating why the desired behaviour was unable to be achieved. Leaving the issue open would also encourage pull requests.
As noted in https://github.com/select2/select2/issues/3415 and on the mailing list, I'm open to the idea of automatically focusing the search on a multiple select when the selection area is focused. I think this would fix the major usability problem (the multiple select looks like a search box but doesn't act like one), but it would still leave the difference in behaviour between the multiple and single select.
Right now there are two UX issues that are a result of this in 4.0.0:
This also increases the minimum number of key presses to select an item in 4.0.0 to 5, which is up from 4 in 3.5.2 and 3 in a native select.
Here are the key sequences that I've been using to measure this UX issue in 4.0.0. All of these are done using Chromium 43 on Ubuntu 14.04.
Default <select>
- never opening the dropdown (optimal)
http://jsbin.com/kawoxenofa/1/edit?html,js,output
Default <select>
- with opening the dropdown
http://jsbin.com/kawoxenofa/1/edit?html,js,output
Select2 4.0.0
http://jsbin.com/kawoxenofa/3/edit?html,js,output
Select2 3.5.2
http://jsbin.com/kawoxenofa/2/edit?html,js,output
Is there stopgap fix for this? This is kind of a dealbreaker for me when using the multiselect. You should be able to tab to it and start typing. I'm about to go back to 3.X
Is there stopgap fix for this?
If you are interested in using the unstable builds (I guess you could say "not released", they're relatively stable), the fix for multiple selects landed yesterday in https://github.com/select2/select2/commit/02cca7baa7b78e73cdcf393172ee3a54be387167.
Thanks for the tip. I tried it, but the copy from today isn't working in IE 9 (the combo box isn't being hidden), so I'll just keep an eye out for the next stable release.
Does anybody have an idea when is v4.0.1 coming? Not a huge fan of monkeypatches.
Does anybody have an idea when is v4.0.1 coming? Not a huge fan of monkeypatches.
We're aiming to release 3.5.3 (probably the last of the 3.5.x line) this weekend. Then we can start focusing on 4.0.1, which will be released when this milestone has no open tickets.
+1. It is an important accessibility feature. I proposed a workaround here.
+1
+1
+1
+1
+1
+1
@select2 any news on this?
@select2 any news on this?
It's fixed for multiple selects, that patch landed in 4.0.1. For single selects, no "good" solution has been found yet, but we're open to ideas.
Opening the search box on the keypress event would be better than nothing. http://jsfiddle.net/n2en77vt/
Feel free to improve.
It may not be an ideal solution in all case, but at least when doing tab, start typing, you see what is done and just have to type enter to validate the selection. For me, it's sufficient.
Maybe it could be possible, on a keypress, to :
and, such, having the same behaviour as a classic select.
Not sure if it's of interest to anyone, but I hacked a solution using jquery:
$(document).on('focus', 'span.select2', function () {
$(this).prev('select:not([multiple])').select2('open');
});
@jgeurts : Open on focus is interesting, but IMHO it's too much. Let's consider a form with input / select 2 / input, if I press 3 times Tab, it won't do what I think it will do. But I suppose it's a matter of taste.
See my answer above (and the fiddle) for opening the select2 only on a keypress.
@Yopai Timeout seems to be required http://jsfiddle.net/9zmco28f/1/
I understand you had your reason for changing the default behavior, but we are using Select2 on a long-term project and need to provide existing users the UX they are used from 3.5.x (opening the select2 on keypress, without typing return first.).
IMO there should at least be an option to use the old select2 opening behavior for legacy projects.
+1
Current implementation seems to only allow search on single select when the dropdown is open AND there is a search box present. I'm regretting upgrading at this point. Not providing search on initial focus seems like a big deal. Would it be possible to track keypresses on the focus div and just append to an in-memory string, rather than changing focus to a DOM element, resetting the string after a reasonable timeout?
Would it be possible to track keypresses on the focus div and just append to an in-memory string, rather than changing focus to a DOM element, resetting the string after a reasonable timeout?
This doesn't work well with odd keyboards, non-English languages, and numeric keypads. See https://github.com/select2/select2/issues/3279#issuecomment-96450069.
So, the way I understand it, using an input as the focus element is the only (known) way to correctly capture the keyboard input on all keyboards, but it has 2 negative side effects... 1) it shows the keyboard on touch devices, and 2) it was not picked up by some screen readers. Is that a good summary?
@kevin-brown I'd really need a solution for this. Can you give specific requirements for how this needs to behave to be acceptable? Also, worth noting, at least on my iPhone 5, the mobile keyboard does display on tap under the current example (one of the issues against using an input as the focus element, i thought).
Below is a codepen showing my partial solution to the issue, using an adapter. The technique transfers focus from the $selection
element to the $search
element on keydown
. This seems to correctly capture the input in the search box (which must be enabled for this to work). Since this doesn't change the initial focused element, I assume it will still be fine for screen readers. I have tested this in IE11, and recent versions of FF, Chrome and Safari (Mac).
This is a crippling missing feature that has caused me to toss out Select2 as an option for my application.
I get that Select2 is free and you are totally under no obligation to fix it, but I thought you might be interested in knowing that even though I would rather go with Select2, I can't. Without the "closed" selection via typing and arrow keys that a normal select box (and so many other select replacements) fully support the difference in the user experience is just too jarring for most users.
OK, so Chosen did not work out for me so I was back to Select2. I found a way to make it support typing in place for searching. I only tested it for single select and YMMV.
Here is the code (typescript):
// At the class level:
inlineSearchString: string = '';
inlineSearchTimeoutId: any;
// In a setup somewhere
//+ Add the ability to just type in the item you want.
selectBox.keypress(event => {
var key = event.which;
if (key >= 32) {
// If we don't get a keystroke after a bit, then we will reset the
// inline filter so that they can start a new search.
clearTimeout(this.inlineSearchTimeoutId);
this.inlineSearchTimeoutId = setTimeout(() => {
this.inlineSearchString = '';
}, 750);
let char = String.fromCharCode(key);
let inlineSearch = this.inlineSearchString = this.inlineSearchString + char;
let allOptions = originalSelect.find('option');
// A filter of `option[value*='${inlineSearch}']` was tried and it returned 0 results.
// So a manual filter on the function was put in even though it is not as clean.
let filteredList = allOptions.filter(function(index) {
if (inlineSearch && this.value) {
let optionMatchRegExp = new RegExp('^'
+ inlineSearch.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), "i");
let result = optionMatchRegExp.test(this.value);
return result;
} else {
return false;
}
});
let newValue = filteredList.first().val();
if (newValue) {
originalSelect.val(newValue);
originalSelect.trigger('change');
}
}
});
In the above code, selectBox
is the Select2 select box (the root span). originalSelect
is the element that is the actual <select>
tag that you put in your code.
This is how I solved the "open on keypress". Your solution will not work with AJAX and it alters the selection behavior. I think it is better to just open the control and send the key code that the user typed and then benefit from the builtin behavior.
/*
* An unfortunate restriction of Select2 v4 is that there is no backing <input> and it will
* not open until you press enter or space.
* https://github.com/select2/select2/issues/3279
*/
// noinspection JSUnusedGlobalSymbols
@HostListener('window:keydown', ['$event'])
onKeyDown(ev: KeyboardEvent) {
/* we're only interested when the open on keypress behavior is enabled */
if (!this.openkeypress) {
return;
}
/* quick test that it is a select2 element to not cause a performance drag */
if ((<any>ev.target).className.indexOf('select2-selection') === -1) {
return;
}
let $target = jQuery(ev.target).closest('.select2-container');
if (!$target.length) {
return;
}
/* not if it is already open */
if ($target.hasClass('select2-container--open')) {
return;
}
$target = $target.prev();
/* check if it belongs to this component instance */
if (!$target.length || !$target[0].isEqualNode(this.element[0])) {
return;
}
if (ev.which >= 32) {
this.element.select2('open');
let $search = this.element.data('select2').dropdown.$search || this.element.data('select2').selection.$search;
/* Safari does not have key */
let key = ev.key ? ev.key : String.fromCharCode(ev.which);
/* filter function keys such as "Meta" */
if (key.length === 1) {
$search.val(key);
}
// Timeout seems to be required for Blink
setTimeout(() => {
$search.get(0).setSelectionRange(1, 1);
$search.trigger('keyup');
}, 0);
}
}
I started with the code from @achimha and ended up with this:
$('.select2-selection').keydown((ev) => {
if (ev.which < 32)
return;
var target = jQuery(ev.target).closest('.select2-container');
if (!target.length)
return;
target = target.prev();
target.select2('open');
var search = target.data('select2').dropdown.$search ||
target.data('select2').selection.$search;
/* Safari does not have key */
var key = ev.key ? ev.key : String.fromCharCode(ev.which);
/* filter function keys such as "Meta" */
if (key.length === 1)
search.val(search.val() + key);
});
It works even when you type really fast :)
So to be clear, no official support for this feature is coming for single-select? Any news on this?
Native dropdowns will search for a value when focused and a key is pressed. I don't understand why that functionality is not at least supported here.
+1
I modified the library with the following (borrowing from @turekl):
// Line #5368
this.on('keypress', function (evt) {
var key = evt.which;
if (self.isOpen()) {
if (key === KEYS.ESC || key === KEYS.TAB ||
(key === KEYS.UP && evt.altKey)) {
self.close();
evt.preventDefault();
} else if (key === KEYS.ENTER) {
self.trigger('results:select', {});
evt.preventDefault();
} else if ((key === KEYS.SPACE && evt.ctrlKey)) {
self.trigger('results:toggle', {});
evt.preventDefault();
} else if (key === KEYS.UP) {
self.trigger('results:previous', {});
evt.preventDefault();
} else if (key === KEYS.DOWN) {
self.trigger('results:next', {});
evt.preventDefault();
}
} else {
if (key === KEYS.ENTER || key === KEYS.SPACE ||
(key === KEYS.DOWN && evt.altKey)) {
self.open();
evt.preventDefault();
} else {
if (key === KEYS.SHIFT || key === KEYS.CTRL || key === KEYS.ALT || key === KEYS.TAB)
return;
target = self.$container;
if (!target.length)
return;
target = target.prev();
self.open();
var search = target.data('select2').dropdown.$search ||
target.data('select2').selection.$search;
/* Safari does not have key */
var key = evt.key ? evt.key : String.fromCharCode(evt.which);
/* filter function keys such as "Meta" */
if (key.length === 1)
search.val(search.val() + key);
}
}
});
Seems like a simple fix to the library, not sure what the issue is. Any improvements are welcome.
My original fix stopped working in Firefox on Linux (it's still OK on Windows). I found another, even simpler solution, only setting focus to the search field:
$('.select2-selection').keydown((ev) => {
if (ev.which < 32)
return;
var target = jQuery(ev.target).closest('.select2-container');
if (!target.length)
return;
target = target.prev();
target.select2('open');
var search = target.data('select2').dropdown.$search ||
target.data('select2').selection.$search;
search.focus();
});
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This is still an issue as far as I know. It is stale only because there is no movement on any kind of fix.
Just done a migration of a project which required updating our Select2 library.
To which, I was surpised to find tabbing into the select2 field and typing didn't work naturally like it did in 3.*.
A number of workarounds on this long thread I can see here - each with their own use-case. I'd agree with an eariler poster, would of been great if there was a legacy option to allow this behaviour.
Although I guess not many people are upgrading from version 3
to 4
these days as was before.
See also #5993
On the examples page for 3.5.2, if you use the tab key to give a select box focus and start typing, a search of the options begins, as desired.
On the examples page for 4.0, if you do the same thing, nothing happens. You are required to actually click the dropdown in order for searching to begin.
This is no good - I want my users to be able to tab through a form and, when they reach a dropdown, to be able to just start typing to begin searching, and use the enter key to make a selection. In other words, I don't want to users to have to use the mouse at all if they don't want to, which with 3.5.2 is possible, but with 4.0 is not.