Remove focus from textbox when iscroll region is clicked - javascript

I have defined some events when input textbox has got focus and some task to perform when focus is removed. I am also using iscroll4 but textbox is out of the scroller. My problem is when textbox gets focus and i click on the iscroll area the foucs from textbox is not going. But if i click on area outside iscroll the foucs is removing from the textbox. I am not understand why clicking on the iscroll region does not remove the focus whereas click events work. I have defined the blur event.

I am using iscroll4 and in the iscroll.js file there is the following event defined :
onBeforeScrollStart: function (e) {
if (e.preventDefault) {
e.preventDefault();
}
}
I commented the e.preventDefault line and it worked for me. This was basically preventing the blur event to fire when i clicked on the iscroll region because this is the first event that iscroll fires when it receives any mouse down event.

Related

Input focus and blur firing when window gets focus

I have a text input on a page to which I have bound focus() and blur() events. I'm having an issue where focus and then blur are firing unexpectedly if I follow the these steps:
Click on input, focus() fires. OK.
Click out of window on another window, blur() fires. OK.
Click back on original window, focus() and then blur() on the input both fire. PROBLEM!
$('#password').focus(function(){
$('#passwordStrength').slideDown(500);
}).blur(function(){
$('#passwordStrength').slideUp(500);
});
I really need the focus() and blur() events not to fire when the window regains focus as it causes a div to quickly appear and then disappear.
Any ideas on how to stop this?
I ended up getting around this by checking if the document has focus as part of my blur function.
$('#password').focus(function(){
$('#passwordStrength').slideDown(500);
}).blur(function(){
if (document.hasFocus()) {
$('#passwordStrength').slideUp(500);
}
});
This means that my strength box stays on the page when clicking away and then behaves appropriately when clicking back into the window.
Thanks to the commenters for trying to help and sending me on the right path.
You can use window.onfocus to detect if the current tab is focused.
function focus () {
$('#password').focus(function(){
$('#passwordStrength').slideDown(500);
}).blur(function(){
$('#passwordStrength').slideUp(500);
});
}
focus();
window.onfocus = function () {
$('#password').focus();
focus();
}
Here the fiddle

How to hide widget on blur except when widget is clicked?

I'm building a widget akin to a datepicker, but I can't figure out how to make it disappear when when either (a) the user tabs out of the input box, or (b) clicks outside both the widget and input.
It's easy to bind a blur event to the input box, but the problem is that it will get triggered when you click on the widget, and there doesn't appear to be a reliable way to determine which element the focus was changed to from inside the blur event.
Closing the widget when the user clicks outside of the input is a bit sketchy too, but it's doable:
$('body').on('click', function(e) {
if(e.target != self.element[0] && e.target != self.clock[0] && !$.contains(self.clock[0], e.target)) {
self.clock.hide();
}
});
But I wouldn't need that if I could figure out how to handle the blur event properly (which may also be triggered by tabbing outside of the element).
Turns out the solution is actually quite simple. Thanks to rojoca's suggestion, I came up with this:
this.timepicker.on('mousedown', function(e) {
return false;
});
this.element.on('blur', function(e) {
self._parseInput();
self._refreshInput();
self._close();
});
The mousedown event fires first, and by returning false it prevents the blur event from triggering when clicking on the widget. Everything else (clicking outside the widget and input box, or tabbing away) causes a blur, which closes the widget as desired.
Further, it had the unintended by pleasant side-effect of keeping your cursor inside the textbox while interacting with the widget.

onclick() and onblur() ordering issue

I have an input field that brings up a custom drop-down menu. I would like the following functionality:
When the user clicks anywhere outside the input field, the menu should be removed.
If, more specifically, the user clicks on a div inside the menu, the menu should be removed, and special processing should occur based on which div was clicked.
Here is my implementation:
The input field has an onblur() event which deletes the menu (by setting its parent's innerHTML to an empty string) whenever the user clicks outside the input field. The divs inside the menu also have onclick() events which execute the special processing.
The problem is that the onclick() events never fire when the menu is clicked, because the input field's onblur() fires first and deletes the menu, including the onclick()s!
I solved the problem by splitting the menu divs' onclick() into onmousedown() and onmouseup() events and setting a global flag on mouse down which is cleared on mouse up, similar to what was suggested in this answer. Because onmousedown() fires before onblur(), the flag will be set in onblur() if one of the menu divs was clicked, but not if somewhere else on the screen was. If the menu was clicked, I immediately return from onblur() without deleting the menu, then wait for the onclick() to fire, at which point I can safely delete the menu.
Is there a more elegant solution?
The code looks something like this:
<div class="menu" onmousedown="setFlag()" onmouseup="doProcessing()">...</div>
<input id="input" onblur="removeMenu()" ... />
var mouseflag;
function setFlag() {
mouseflag = true;
}
function removeMenu() {
if (!mouseflag) {
document.getElementById('menu').innerHTML = '';
}
}
function doProcessing(id, name) {
mouseflag = false;
...
}
I was having the exact same issue as you, my UI is designed exactly as you describe. I solved the problem by simply replacing the onClick for the menu items with an onMouseDown. I did nothing else; no onMouseUp, no flags. This resolved the problem by letting the browser automatically re-order based on the priority of these event handlers, without any additional work from me.
Is there any reason why this wouldn't have also worked for you?
onClick should not be replaced with onMouseDown.
While this approach somewhat works, the two are fundamentally different events that have different expectations in the eyes of the user. Using onMouseDown instead of onClick will ruin the predictability of your software in this case. Thus, the two events are noninterchangeable.
To illustrate: when accidentally clicking on a button, users expect to be able to hold down the mouse click, drag the cursor outside of the element, and release the mouse button, ultimately resulting in no action. onClick does this. onMouseDown doesn't allow the user to hold the mouse down, and instead will immediately trigger an action, without any recourse for the user. onClick is the standard by which we expect to trigger actions on a computer.
In this situation, call event.preventDefault() on the onMouseDown event. onMouseDown will cause a blur event by default, and will not do so when preventDefault is called. Then, onClick will have a chance to be called. A blur event will still happen, only after onClick.
After all, the onClick event is a combination of onMouseDown and onMouseUp, if and only if they both occur within the same element.
Replace on onmousedown with onfocus. So this event will be triggered when the focus is inside the textbox.
Replace on onmouseup with onblur. The moment you take out your focus out of textbox, onblur will execute.
I guess this is what you might need.
UPDATE:
when you execute your function onfocus-->remove the classes that you will apply in onblur and add the classes that you want to be executed onfocus
and
when you execute your function onblur-->remove the classes that you will apply in onfocus
and add the classes that you want to be executed onblur
I don't see any need of flag variables.
UPDATE 2:
You can use the events onmouseout and onmouseover
onmouseover-Detects when the cursor is over it.
onmouseout-Detects when the cursor leaves.
onFocus / onBlur are events that don't bubble. There are however focus events that do bubble. These being focusin and focusout.
Now to the solution: We wrap both the input and our dropdown into a div-element and set the tabindex of that div to -1 (so that it can recieve focus / but does not appear in the tab order). We now add an eventlistener for focusin and focusout to this div. And since these events do bubble a click on our input element will trigger our divs focusin event (which opens the drop-down)
The neat part now is that a click on our dropdown will also trigger the focusin event on our div (so we basically maintain focus which means: focusout/blur never fires and our dropdown stays open)
You can try this out with the code snippit below (the dropdown only closes on loss of focus - but if you want it to close when clicking on the dropdown aswell just uncomment the one line of JS)
const container = document.getElementById("container")
const dropDown = document.getElementById("drop-down")
container.addEventListener("focusin", (event) => {
dropDown.classList.toggle("hidden", false)
})
container.addEventListener("focusout", (event) => {
dropDown.classList.toggle("hidden", true)
})
dropDown.addEventListener("click", (event) => {
console.log("I - the drop down - have been clicked");
//dropDown.classList.toggle("hidden", true);
});
.container {
width: fit-content;
}
.drop-down {
width: 100%;
height: 200px;
border: solid 1px black
}
.hidden {
display: none
}
<div class="container" id="container" tabindex="-1">
<input id="input" />
<div class="drop-down hidden" id="drop-down" > Hi I'm a drop down </div>
</div>
there arises however one issue if you want to add your dropdown into the tabbing order, have buttons in your dropdown or in general have an element in the dropdown, that can recieve focus. Because then a click will give the element in the dropdown focus first. This triggers our container div to lose focus which closes the dropdown so the focus event can't bubble further and therefore can't trigger the focusin on our container.
We can solve this issue by expanding the focusout eventlistener a bit.
The new eventlistener is as follows:
container.addEventListener("focusout", (event) => {
dropDown.classList.toggle("hidden", !container.matches(":hover"))
})
We basically say: "don't you close that dropDown if someone is hovering over it" (This solution only considers mouse-use; but in that case this is fine, because the problem this tries to fix only ever occured when using a mouse, when tabbing onto/through the dropDown everything worked fine from the start)
change onclick by onfocus
even if the onblur and onclick do not get along very well, but obviously onfocus and yes onblur. since even after the menu is closed the onfocus is still valid for the element clicked inside.
I did and it worked.
An ideal solution I found to work for me was to simply add a timeout in my onBlur function. I used 250ms, that provided smooth behaviour for my blur event and allowed my onClick to fire before the onBlur. I used this example as a reference https://erikmartinjordan.com/onblur-prevents-onclick-react
You can use a setInterval function inside your onBlur handler, like this:
<input id="input" onblur="removeMenu()" ... />
function removeMenu() {
setInterval(function(){
if (!mouseflag) {
document.getElementById('menu').innerHTML = '';
}
}, 0);
}
the setInterval function will remove your onBlur function out from the call stack, add because you set time to 0, this function will be called immediately after other event handler finished

Draggable cancel triggering blur event

I have a draggable div which of course could be dragged around.
Inside, I have input text which has two events (focus and blur).
Also inside, I have another div which serve as draggable cancellation div (dragging that div prevent any drag to occur).
you could see it here:
http://jsfiddle.net/wUDzh/4/
Clicking the input box would trigger focus event and clicking outside main div (the red one) would trigger blur event. This is fine.
Clicking or dragging the main div would NOT trigger blur event. That's what I want.
The problem is, clicking the cancellation div (the blue one) cause blur event of the input box to occur. Which is make sense, but that's not what I want.
is there any way to prevent blur event to occur just like the behavior of the main div?
thx
To prevent the input field from blurring when you click the cancellation div, simply do:
$('#cancel').mousedown(function(e) {
e.preventDefault();
});
See fiddle
You could do
$("#text").blur(function(e)
{
// alert('a');
if(e.target.id === 'text'){
//this prevents other blur handlers from firing
e.stopImmediatePropagation();
//this prevent the default action and returns
return false;
}
$(this).val("I've got blur");
});
fiddle here http://jsfiddle.net/wUDzh/6/

jQuery blur handler not working on div element?

I don't understand why the jQuery blur handler isn't working in the most simple case. I'm literally creating a div 100px by 100px and setting a blur event on it, but it's not firing (JSFiddle):
<div id="test">this is a test</div>
$(document).ready(function() {
$('#test').bind('blur', function() {
alert('blur event!');
});
});
Is my understanding of blur wrong? I expect the blur event to fire when I click anywhere that is not the div...right?
According to jQuery's documentation:
In recent browsers, the domain of the event has been extended to
include all element types. An element can lose focus via keyboard
commands, such as the Tab key, or by mouse clicks elsewhere on the
page.
I've tried it on the latest Chrome and Firefox on Mac.
From the W3C DOM Events specification:
focus
The focus event occurs when an element receives focus either via a pointing device or by
tabbing navigation. This event is valid for the following elements: LABEL, INPUT, SELECT,
TEXTAREA, and BUTTON.
blur
The blur event occurs when an element loses focus either via the pointing device or by
tabbing navigation. This event is valid for the following elements: LABEL, INPUT, SELECT,
TEXTAREA, and BUTTON.
The jQuery docs state browsers extended the events to other elements, which I'm guessing means blur and focus are aliases for the more generic DOMFocusIn and DOMFocusOut events. Non-input elements aren't eligible to receive those by default though, and an element has to somehow gain focus before losing it - a blur still won't fire for every click outside the div.
This SO question mentions that giving an element a tabindex would allow that, and seems to work for me in Chrome after modifying your jsFiddle. (Albeit with a fairly ugly outline.)
As far as I knew, blur happens on inputs that had the focus, either way you say
I expect the blur event to fire when I click anywhere that is not the div...right?
Not exactly, the blur event only happens for an element that had the focus first
So in order for a blur event to occur, you would first have to give focus to the div, how is the div getting focus first?
If you are really try to determine if there was a click outside of your div, you need to attach a click handler to the document, and then check to see where your click came from.
var div_id = "#my_div";
var outsideDivClick = function (event) {
var target = event.target || event.srcElement;
var box = jQuery(div_id);
do {
if (box[0] == target) {
// Click occured inside the box, do nothing.
return;
}
target = target.parentNode;
} while (target);
}
jQuery(document).click(outsideDivClick);
Just remember that this handler will be run for EVERY click on the page. (in the past if i ha to use something like this, i attach the handler when I need it, and remove it when I no longer need to look for it)
A can't "blur" because that would involve the div having focus in the first place. Non-input elements like a and textarea can have focus, which is what jQuery's documentation refers to.
What you need is the "mouseout" or "mouseleave" event (mouseleave doesn't bubble, mouseout does), which will be fired when the cursor leaves the div. If you need to have clicks, I would attach a "click" event to the body, as well as the div and stopping the event propagation on only the div:
$("div").click(function(e) {
return false; // stop propagation
});
Or, if you're really determined, you can fake the appearance of a div with a and some CSS rules :)
If you want something to happen while you move your mouse over the box, you could use the mouseover event.

Categories

Resources