Open bootstrap dropdown on input focus - javascript

I have an input that when clicked shows a bootstrap 4 dropdown BUT I need it to open when a user tabs to it as well for ADA accessibility.
If I use a focus event that uses $('#input-name).dropdown('toggle') it works fine, but when the input is clicked focus fires first which opens the dropdown and then the click event closes it.
I have tried e.preventDefault(); e.stopPropagation(); but neither help solve this issue.
events: {
focus #healthPlanMenu": "openDropDown"
}
openDropDown: function (e) {
if ($('#healthPlanMenu').find('.dropdown-menu:no(.show)')){
$("#healthPlanMenu.dropdown-toggle").dropdown('toggle');
}//fails
$("#healthPlanMenu.dropdown-toggle").dropdown('toggle');//fails
$( "#healthPlanMenu" ).click();//fails
}

So ideally you'd probably solve this by having the focus event set the dropdown's state to open, that way if it gets "reopened" by the click event, no problem. However, as far as I can tell there is only a toggle option with the jQuery API; seems unnecessarily limiting...
Given that, we can know if a click is coming after our focus event by using mousedown. So a somewhat hacky way to solve this problem is to disable our focus event if we know a click is coming.
(function() {
var disable = false;
$('#healthPlanMenu.dropdown-toggle')
.on('mousedown touchstart', function() {
disable = true;
})
.on('focus', function() {
if (!disable) {
$(this).dropdown('toggle');
}
})
.on('mouseup touchend',function() {
disable = false;
})
})()
I don't know if the touchstart and touchend are necessary as most browsers probably fire mouse events on touch as well. But better safe than sorry.

Related

how can I check if a particular item is clicked with .blur() in jquery

I have an autocomplete dropdown that appears when a user starts typing in a textbox (I'm using jquery mobile but I don't think that's important to my problem). I want to be able to hide the whole dropdown list when a user clicks anywhere on the page. However, I don't want to hide the dropdown when a user actually clicks on the dropdown itself.
Is there a way I could catch the click event in order to know what was clicked?
Here's my blur function:
//hide autocomplete when dropdown is not clicked
$("#search-div input").blur(function () {
$("#autocomplete-list").hide();
});
I was thinking of somehow putting an if statement in my blur function. Here's my pseudo code:
if( dropdown clicked)
{
run code to take text from dropdown and place in textbox
}
else
{
hide dropdown
}
Would it be possible to know whether my dropdown is clicked or something else is clicked while in my blur function? When I debug my javascript I'm only seeing an event that's related to the textbox doing the blur()
Edit:
Here is a function I'm using to handle when the dropdown is clicked:
$( document).on( "click", "#autocomplete-list li", function() {
var selectedItem = event.target.innerHTML;
$(this).parent().parent().find('input').val(selectedItem);
$('#autocomplete-list').hide();
runSearchQuery();
});
You can listen for any click, not just a blur, and then check what the clicked element was. e.currentTarget gives you what was clicked.
var clickHandler = function(e) {
if ($(e.currentTarget).hasClass('dropdown')) {
// do nothing
} else {
// Make sure you unregister your event every
// time the dropdown is hidden.
$(window).off('click', clickHandler);
// hide
}
}
// When the dropdown comes down, register an event on the whole page.
$(window).on('click', clickHandler);

.select() not functioning correctly in Chrome

I'll keep it short and sweet. Trying to implement .select in jQuery and it doesn't seem to be cooperating in Chrome. Clicking in to the input selects the contents only briefly.
$(document).on('focus','.a-thing', function () {
this.select();
});
jsFiddle
this is not a jQuery object
$(document).on({
focus : function () {
$(this).select();
},
mouseup : function() {
return false;
}
}, '.a-thing');
FIDDLE
And you have to prevent the mouseup event to avoid loosing the selection as the mouseup event deselects the text, it's a know issue in Chrome.
Probably due to using the focus event. Try to fire the select event after the focus is complete:
$(document).on('focus','.a-thing', function () {
var self = this;
setTimeout(function() {
self.select();
},1);
});
Updated jsFiddle
User click event instead of foucs, because keyboard tab key will auto select field value without foucs event
$(document).on('click','.a-thing', function () {
this.select();
});
JSFIDDLE DEMO
You can active the select on the mouse up instead of the focus. Chrome seems to de-select on the mouse up event.
$(document).on('mouseup','.a-thing', function () {
$(this).select();
});
Or if you want to keep the focus event, you can prevent the action on mouse up
$(document).on('mouseup','.a-thing', function () {
e.preventDefault();
});
On mouseup event the selection is getting unselected, Please add the following to fix the issue
$(".a-thing").mouseup(function(e){
e.preventDefault();
});
DEMO

Jquery ui dialog not closing with `Escape` keypress

When a user opens dialog, there are a bunch of ajax requests that have to be processed and therefore i have a second dialog that just displays loading information and closes once all the requests have been processed.
I am not able to close the user opened dialog with Escape key once it has opened. I have to click on the the dialog itself before I can use escape.
I have tried the following to assign the user opened dialog the focus after the loading dialog closes but to no avail, I still have to click on the dialog before it can close with the escape key.
$(document).ajaxStart(function () {
// IF loading dialog is not allready being shown show it.
if ($("#LoadingData").dialog('isOpen') === false) {
$("#LoadingData").dialog('open');
}
});
$(document).ajaxStop(function () {
//Close the loading dialog once the requests have finished
$("#LoadingData").dialog('close');
//Find the user opened dialog
$('.cmdialog').each(function () {
if ($(this).dialog('isOpen')) {
$(this).trigger('click');//set focus to dialog
// have also replaced .trigger('click') with .focus() but to no avail
}
}).on('click', function() {
//if click is triggerd set the focus of the dialog.
if ($(this).prop('id') != 'LoadingData') {
$(this).focus();
}
});
});
I have also tried setting the focus to the first element within the dialog with $('#DialogName:first-child').focus() and $('#DialogName:first-child').trigger('click') but this is also not working.
Any ideas as to why the focus is not set? Or am I misunderstanding/incorrectly using .focus() and .trigger('event')?
Thanks :)
Try the below code for close the dialog when Escap key is pressed:
$(document).keyup(function(e) {
if (e.keyCode == 27) { $("#LoadingData").dialog('close'); } // esc
});
I had the same issue, and found pretty elegant solution, in case you want to close dialog before actually clicking inside it:
$("#LoadingData").dialog({
...,
focus: function () {
$('#LoadingData').closest('.ui-dialog').focus();
}
});
So, we just need to set focus to parent .ui-dialog container, and in that case Esc will work for all cases. Disadvantage of $(document).keyup solution, if you have nested dialogs, Esc button will close your most top dialog and bottom one too.
the focus event is sent to an element when it gains focus. This event is implicitly applicable to a limited set of elements, such as form elements (, , etc.) and links. docs here
You can try moveToTop method of the dialog, maybe it will help
And in your code, I think, you should bind "click" event before triggering it.
The following code should work even for multiple modals open:
$(document).on('keydown','.modal-dialog',function(event){
if (event.keyCode == 27) {
$(this).closest('.modal-dialog').find('[data-dismiss="modal"]').click();
}
});

jquery autocomplete hides itself on window blur, disable this

jquery's autocomplete is hiding itself on window blur, how to prevent this?
Can't find the answer on the Internet.
Sounds simple but with the following code to determine window focus and blur I get display none for all autocomplete that were opened right before going into blur, seems window blur is the trigger for autocomplete to hide:
$(function() {
$(window).focus(function() {
});
$(window).blur(function() {
$(".ui-autocomplete").each(function(){alert($(this).css("display"));});
});
});
I wanted to set variables for all autocomplete that had a display other than none and then on focus display these, but on blur I get display none for all ".ui-autocomplete"
Try changing the autocomplete's blur event handler like this:
$(function(){
$('#autocomplete').autocomplete({
source: ['cat','rabbit','donkey']
}).off('blur').on('blur', function() {
if(document.hasFocus()) {
$('ul.ui-autocomplete').hide();
}
});
});
Using the hasFocus() function you can check the focus of the current window and determine wether to close the options or not
jsFiddle here

Action on blur except when specific element clicked with jQuery

There are two elements in play:
$('#myInput') // an input field for search
$('#myList') // a list to display search results
I want to hide the list when the input no longer has focus, like so:
$('#myInput').blur(function() {
$('#myList').hide();
});
This works great, except when a list item is clicked, because the blur event fires and hides the list before the click is registered. The goal is for the list to stay visible when any part of the list is clicked, even though this will cause the input to blur.
How can I do this? Thanks!
You can accomplish this by keeping a global variable, and setTimouts, to wait a delay of 200ms and then check if one of the 2 elements have focus.
var keepFocus = false;
function hideList(){
if(!keepFocus){
$('#myList').hide();
}
}
$('#myInput').blur(function() {
keepFocus = false;
window.setTimeout(hideList, 200);
}).focus(function(){
keepFocus = true;
});
$('#myList').blur(function() {
keepFocus = false;
window.setTimeout(hideList, 200);
}).focus(function(){
keepFocus = true;
});
I've faced with the exact same problem, so this is how I solved it.
I came up with the fact that blur() fires earlier than click().
So I've tried to change click() to mousedown() and found out that mousedown() fires before blur().
And to imitate click() you'll have to fire mousedown() and then mouseup()
So in your case I would do something like this:
var click_in_process = false; // global
$('#myList').mousedown(function() {
click_in_process = true;
});
$('#myList').mouseup(function() {
click_in_process = false;
$('#myInput').focus();
// a code of $('#myList') clicking event
});
$('#myInput').blur(function() {
if(!click_in_process) {
$('#myList').hide();
// a code of what you want to happen after you really left $('#myInput')
}
});
Demo / example: http://jsfiddle.net/bbrh4/
Hope it helps!
You need to be able to say "do this blur() unless the list gains focus at the same time".
This question says how to detect if an element has focus: Using jQuery to test if an input has focus
Then all you need to do is:
$("#myInput").blur(function () {
if (!$("#myList").is(":focus")) {
$("#myList").hide();
}
});
Pigalev Pavel's answer above works great.
However, If you want an even simplier solution, you can just "prevent default" in the "mousedown" of an element to prevent the blur event from taking place. (since preventing default actually means that in the end, the input never looses focus in the first place!)
Of course, this is only if you're alright with preventing default in the div. It does have some side-effects, like the text is no longer selectable. As long as that's not an issue, this will work.
I suppose if you hold the mouse down over the div, move the mouse outside of the div, and then release the mouse, it also doesn't fire the "blur" event. But in my case, I wasn't too worried about that either, since the click started in the target div.
$("input").focus(function(){
$(this).val("");
});
$("input").blur(function(){
$(this).val("blur event fired!");
});
$("div").mousedown(function(e){
e.preventDefault();
})
div{
height: 200px;
width: 200px;
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input>
<div>
Click here to prevent blur event!
</div>
The best way to do this is to attach an event handler to the body element, then another handler to the list that stops event propagation:
$(body).click(function () {
$("#myList").hide();
});
$("#myList").click(function (e) {
e.stopImmediatePropagation();
});
This listens for a click outside of #myInput and hides #myList. At the same time, the second function listens for a click on #myList and if it occurs, it prevents the hide() from firing.

Categories

Resources