jQuery Select2 - Use tab to select an option - javascript

I'd like to be able to use the arrow keys to get to the select2 option I want and then press tab to select that option and then tab to the next element as usual.
I already got the down arrow to open the select2 with the following:
$(document).on('keydown', '.select2', function(e) {
if (e.originalEvent && e.which == 40) {
e.preventDefault();
$(this).siblings('select').select2('open');
}
});
And I can also use the arrows to get where I need to go. Now I'm struggling to make the tab part work.
I'm assuming since the select2-search__field has focus at the time I'm pressing the key, that that is the element I bind the event to? And then presumably I need to get the value of the currently highlighted option and trigger the select2 change?
I'm not 100% sure this is the right approach but I can't quite figure it out.

To achieve this you can use selectOnClose: true:
$(document).on('keydown', '.select2', function(e) {
if (e.originalEvent && e.which == 40) {
e.preventDefault();
$(this).siblings('select').select2('open');
}
});
$('select').select2({
selectOnClose: true
});
select {
min-width: 150px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/js/select2.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.5/css/select2.min.css" />
<select>
<option>AAAAA</option>
<option>BBBB</option>
<option>CCCC</option>
<option>DDDD</option>
<option>EEEE</option>
<option>FFFF</option>
<option>GGGG</option>
</select>

Just add following line in your code.
$(document).on("select2:close", '.select2-hidden-accessible', function () { $(this).focus(); });
Your issue will be resolved.

I had this same issue. Because selectOnClose: true also means that pressing Esc or clicking outside of the select dropdown was selecting the input, I have opted for a far more complicated and less elegant solution than the accepted answer. My solution has solved this issue for me (and allows subsequent tabbing to switch focus on down the DOM).
I added a listener to select2:closing (which fires immediately before it closes and thus when the highlighted li is still highlighted). Select2 gives that li an id that contains the value of the option to which it's tied. I parse that out and squirrel it away in state (I'm using Vue):
$(this.subjectSelect2).on('select2:closing', () => {
var idArray = $(".select2-results__option--highlighted")[0].id.split("-");
var id = idArray[idArray.length - 1];
this.select2LastHighlighted = id;
})
I then added a listener for keydown, so that if tab is pressed, it takes that value from state, and updates the select2 to that value:
$(this.subjectSelect2).on('select2:open', () => {
$(".select2-search__field")
.on('keydown', (e) => {
if (e.key == 'Tab') {
this.subjectSelect2.val(this.select2LastHighlighted);
this.subjectSelect2.trigger('change');
}
})
})
I'd love to hear if someone has a more elegant way to do this!

Related

Javascript keypress to make ligh

on a web page how do you enable the user to light up the boxes/items on the page using a specific key on your keyboard? eg. i want M to light up my title and when i press M again it turns it off?
this is what i have so far but feel like it could be cleaned up a lot
$('#abutton').click(function() {
$('#abutton').removeClass('off').addClass('on');
$('#bbutton').removeClass('on').addClass('off');
$('#cbutton').removeClass('on').addClass('off');
$('#dbutton').removeClass('on').addClass('off');
window.scrollTo(0,0);
});
$('#bbutton').click(function() {
$('#abutton').removeClass('on').addClass('off');
$('#bbutton').removeClass('off').addClass('on');
$('#cbutton').removeClass('on').addClass('off');
$('#dbutton').removeClass('on').addClass('off');
window.scrollTo(0,0);
});
$('#cbutton').click(function() {
$('#abutton').removeClass('on').addClass('off');
$('#bbutton').removeClass('on').addClass('off');
$('#cbutton').removeClass('off').addClass('on');
$('#dbutton').removeClass('on').addClass('off');
window.scrollTo(0,0);
});
$('#dbutton').click(function() {
$('#abutton').removeClass('on').addClass('off');
$('#bbutton').removeClass('on').addClass('off');
$('#cbutton').removeClass('on').addClass('off');
$('#dbutton').removeClass('off').addClass('on');
window.scrollTo(0,0);
});
Just add the general class .button to all of them. Then remove on from all .button elements and add on class to exact clicked element.
$('.button').click(function() {
$('.button').removeClass('on').addClass('off');
$(this).removeClass('off').addClass('on');
window.scrollTo(0,0);
});
You need to add addEventListener to your code and check inside it if the pressed key has keyCode you're expecting to do some action. Look on example below:
addEventListener("keydown", (event) => {
if (event.keyCode === '13')
//light on/off
});
Please check docs for more details
EDIT: jQuery also has its keyboard events

<input type="date"> event listener: How to distinguish mouse select vs. keyboard input

I use the native HTML date pickers. I want to achieve that the parent form is submitted when a date is selected by the datepickers browsers provide.
If the date is input by keyboard, I only want to submit if the enter key is pressed or on focusout.
Now my problem is that I cannot distinguish between date picker input and keyboard input, at least in Firefox. Some examples:
$(this).on('input', function(event) {
console.log(event.type);
}
This always logs 'input', no matter what I do - I would have expected that to be either "click" or "keydown" or something alike.
The on('click') handler only fires when I click on the input field, not when I click something in the date picker...
Can someone push me in the right direction?
Thanks alot
Philipp
I did a workaround which is close to what I want:
$('#eooMainForm input[type="date"]')
.each(function() {
$(this).data('serialized', $(this).serialize());
$(this).on('focusout', function() {
if($(this).serialize() != $(this).data('serialized')) {
$("#eooMainForm").form('submit');
}
});
$(this).on('keypress', function(event) {
$(this).data('byKeyPress', 1);
});
$(this).on('click', function(event) {
$(this).data('byKeyPress', 0);
});
$(this).on('change', function(event) {
//if change was done by date picker click
if($(this).data('byKeyPress') != 1 && $(this).serialize() != $(this).data('serialized')) {
$("#eooMainForm").form('submit');
}
});
});
So a keypress event listener sets the "flag" "byKeyPress" to 1, while a click events listener sets it to zero. This way, I can determine in the change event listener what caused the change.
The only situation where this does not work is when a user starts typing the date but then selects it by clicking the datepicker. I can live with that.
You'll need to attach an event which supports both event types. Using JQuery: $('a.save').bind('mousedown keypress', submitData(event, this));
Then create a JS condition:
function submitData(event, id)
{
if(event.type == 'mousedown')
{
// do something
return;
}
if(event.type == 'keypress')
{
// do something else
return;
}
}
You can find all the list of event in this image.
$('input').on('blur', function(event) {
alert(event.type);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" />
You can apply all event like the above example. Above example applied blur event on input.

How to run once function on scroll up and scroll down event?

How to run doSomething() once when scrolling up or scrolling down?
window.onscroll = function(e) {
// scrolling up
if(this.oldScroll > this.scrollY){
doSomething();
// scrolling down
} else {
doSomething();
}
this.oldScroll = this.scrollY;
};
The doSomething() bind some elements and I don't want to do repeat binds. I Just want when on scrolling up, bind once and when on scrolling down bind once.
If you mean, your function should be executed once per each scroll event, then your code should do the job already.
However, if you mean you want your function to only be executed first time when the user scrolls, the code can look like this:
window.onscroll = function(e) {
if (this.oldScroll > this.scrollY) {
doSomething();
} else {
doSomethingElse();
}
this.oldScroll = this.scrollY;
delete window.onscroll;
};
Do NOT rely on any kind of "flag variables" as it is proposed above. It is a very bad practice in this scenario!
You can have an option of defining the closure function and using it in a way like described in this post
Apart from the above post I came across this situation and i used the following method to check if the event is already registered or not see below function where I needed to bind the click once only I used typeof $._data ( elementClose.get ( 0 ), 'events' ) === 'undefined' to get the events registered with the element, $._data is used to retrieve event handlers registered to an element/
this.closeButtonPreview = () => {
let elementClose = $("a.close-preview");
if (typeof $._data(elementClose.get(0), 'events') === 'undefined') {
elementClose.on('click', function(e) {
e.preventDefault();
let container = $(this).parent();
container.find('video').remove();
$("#overlay,.window").effect("explode", {}, 500);
});
}
return;
};
EDIT
Just to get the concept clear for you about the logic I used with $._data(). i created an example below.
What i am doing is binding event click to anchor with id=unique inside the condition if (typeof $._data(uniqueBind.get(0), 'events') == 'undefined') { which determines if an event is assigned to the element and binding the event click to the anchor id=multi outside the condition without checking binded events on the element.
What you have to do.
Initially the button unique and multi won't log anything to console, click on EVENT BINDER once and then click on both unique and mutli they both will log text once in console, but as you keep clicking on the EVENT BINDER notice that clicking the multi button will start logging the text as many times as you have clicked the EVENT BINDER button but the unique button will only log once no matter how many times you click on the EVENT BINDER button.
$(document).ready(function() {
$('#binder').on('click', bindEvents);
$('#clear').on('click', function() {
console.clear();
})
});
function bindEvents() {
var uniqueBind = $('#unique-bind');
var multiBind = $('#multi-bind');
//will bind only once as many times you click on the EVENT BINDER BUTTON
//check if any event is assigned to the element
if (typeof $._data(uniqueBind.get(0), 'events') == 'undefined') {
uniqueBind.on('click', function() {
console.log('clicked unique bind');
});
}
//will log the text EVENT BINDER * TIMES_EVENT_BINDER_CLICKED button
multiBind.on('click', function() {
console.log('clicked multi bind');
});
}
body {
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
EVENT BINDER
CLEAR CONSOLE
<br /><br /><br /><br />
UNIQUE
MULTI

find select option with selected property using javascript

I have a view that loads select elements dynamically into the page on certain button clicks. Each of these selects have the same id value followed with an index value based on how many times the button is clicked. so the id would be like
id="my_id_" + numOfClicks;
I have also given all these selectors the same class value
class="selects"
What is the best way to have an event handler for when the selected option changes in any of the drop downs. right now I have the following:
$('.selects').change(function() {
if($('this option:selected').val() == 0) {
}
else {
}
});
So what I'm trying to do is first get the right select element using "this" then figure out which of the options are selected. Is there a better/more efficient way to do this?
As you say these get added at runtime, you'll want a delegated event handler. Within the handler, as the comments have pointed out, it's just $(this).val() to get the selected value of that select box. So:
$("selector for some container they're in").on("change", ".selects", function() {
if($(this).val() == 0) {
}
else {
}
});
For instance, if they're all inside an element with the class container, then:
$(".container").on("change", ".selects", function() {
if($(this).val() == 0) {
}
else {
}
});
If there's no other suitable container, you can just use $(document).on(..., but usually it's better to handle things a bit closer to where they are than that.
Side note: Values are always strings, but == will coerce, so "0" == 0 is true. Still, it's useful to remember that they're strings.
Assuming html input.selects:
$('body').on('change', '.selects', function() {
if($(this).val() == '0') {
}
else {
}
});
http://jsfiddle.net/r4pxx0yy/1/
No quote around this.

jQuery checkbox click shows input field - doesn't work

I use a jQuery function to show certain hidden text fields once you select something from a select box.
This works fine for select boxes but I can't get it to work for a checkbox.
Here is the stripped code I tried (in a nutshell) but it's not working: http://jsbin.com/uwane3/2/
Thanks for your help, I rarely use JS so my knowledge is small.
I have found 2 errors in your code:
your Checkbox has no value so you cant get more than an empty result form ".val()"
you have not bind a eventhandler to the checkbox.
http://jsbin.com/uwane3/3
$('#cf3_field_9').live('click', function(e){
if (e.target == $('#cf3_field_9')[0] && e.target.checked) {
alert('The following line could only work if the checkbox have a value.');
$.viewMapcf3_field_9[$(this).val()].show();
} else {
$.each($.viewMapcf3_field_9, function() { this.hide(); });
}
});
You have no events registered to your checkbox.
Register a click, or change handler like this:
$('#cf3_field_9').click(function(){
if ($(this).attr("checked")) {
$.viewMapcf3_field_9[$(this).val()].show();
} else {
$.each($.viewMapcf3_field_9, function() { this.hide(); });
}
});
http://api.jquery.com/category/events/

Categories