jQuery - raise event when focus leaves a group of controls - javascript

I have 3 textboxes within a div and I need to raise an event when focus leaves one of those inputs and doesn't go to another one of these 3 inputs.
As long as the user is editing one of these 3 controls, the event wont raise. The event will only raise when the focus has changed to a control which isn't one of these inputs.
I tried using focusout on all 3 inputs and checking if document.ActiveElement is one of the 3 inputs but focusout of one control occurs before focusin on another so document.ActiveElement is always empty.
Anyone has any idea how to get around this?

I would consider using a timer to solve this tricky dilemma.
When focus is lost, start the timer. Then you can cancel the timer if focus is then set upon another "safe" input.
Something like this:
var timeoutID;
$("#TheSafeZone input").focus(function () {
if (timeoutID) {
clearTimeout(timeoutID);
timeoutID = null;
}
});
$("#TheSafeZone input").blur(function () {
releaseTheHounds();
});
function releaseTheHounds() {
timeoutID = setTimeout(function () {
alert("You're all going to die down here");
}, 1);
}
Here is a working example
NOTE: I have set the timeout to just 1ms, this seems to work reliably for me but it may be worth doing a few tests in other browsers (I am using Chrome). I guess it is down to how the JS engine handles events, but I don't know enough about that to confidently say all browsers will work the same

Put "Blur" and "Focus" events with opposite logic so that when ever user leaves group of controls specified in DIV only "Blur" event will be fired.
$(document).on("blur","#edit-area .form-control", function (event) {
$('.editButtons').show();
});
$(document).on("focus","#edit-area .form-control", function (event) {
$('.editButtons').hide();
});

Related

Remove touchpointer in javascript

I was trying to make a webapp with html elements that will move form div to antoher div when clicked but also I want to be able fire event when users hold that element for more than a second. So I have this code
$(document).on("click",'.card', function() {
var card=$(this).parent();
if(card.parent().attr('id')==="options"){
card.appendTo("#choice");
}
else{
card.appendTo("#options");
}
});
var timeoutId = 0;
$('.card').on('pointerdown', function() {
timeoutId = setTimeout(showModal, 1000);
}).on('pointerup mouseleave', function() {
clearTimeout(timeoutId);
});
And it is doing almost fine. The problem occures when the element is clicked. It is appended to different div as it should but the mobile pointer is still on it so when I try to fire 'hold' event on another element it is not working for the first time since 'pointerup' event from previous element is firing right after 'pointerdown' event (So you need to try to hold next element twice).
I've dealt with it by adding a simple boolean flag in click event function so it is blocking next first call of 'pointerup' event but this is a very ugly solution.
Do you have any ideas how can i improve this? Maybe there is a way to call 'pointerup' event manually after click?
Removing 'mouseleave' event and adding 'pointerleave' instead fixed the problem.
Not really sure how 'mouseleave' event was fired on mobile device though.

mouseLeave is trigged on native input autofil

I need to show my pop-up when the mouse leaves the <body>, this identifies an exit intention.
So when my clients are typing their emails, the popup just appears at the exact moment their pointer is over the suggestion and it should not have happened. But it happens because this part is not in the DOM, so it triggers the mouse leave
however, this event is triggered when the mouse is over a native input suggestion on browsers (I tested on Firefox and Chrome).
So, any ideas how can I skip this fake trigger?
document.body.onmouseleave = function(e) {
console.log("mouse leave was trigged")
}
Take a look what is happen:
I've encountered the same issue, solved it by looking at what exactly triggered the mouseleave event. So if it was not an input field from your form, you could proceed and show your popup
$('body').on('mouseleave', function (e) {
if ('INPUT' !== e.target.nodeName) {
// do your stuff
}
});

How to run a function only once when it's triggered by both focus and click events

I have an input element with 2 events attached: focus and click. They both fire off the same helper function.
When I tab to the input, the focus event fires and my helper is run once. No problems there.
When the element already has focus, and I click on it again, the click event fires and my helper runs once. No problems there either.
But when the element does not have focus, and I click on it, BOTH events fire, and my helper is run TWICE. How can I keep this helper only running once?
I saw a couple similar questions on here, but didn't really follow their answers. I also discovered the .live jQuery handler, which seems like it could work if I had it watch a status class. But seems like there should be a simpler way. The .one handler would work, except I need this to work more than once.
Thanks for any help!
The best answer here would be to come up with a design that isn't trying to trigger the same action on two different events that can both occur on the same user action, but since you haven't really explained the overall problem you're coding, we can't really help you with that approach.
One approach is to keep a single event from triggering the same thing twice is to "debounce" the function call and only call the function from a given element if it hasn't been called very recently (e.g. probably from the same user event). You can do this by recording the time of the last firing for this element and only call the function if the time has been longer than some value.
Here's one way you could do that:
function debounceMyFunction() {
var now = new Date().getTime();
var prevTime = $(this).data("prevActionTime");
$(this).data("prevActionTime", now);
// only call my function if we haven't just called it (within the last second)
if (!prevTime || now - prevTime > 1000) {
callMyFunction();
}
}
$(elem).focus(debounceMyFunction).click(debounceMyFunction);
This worked for me:
http://jsfiddle.net/cjmemay/zN8Ns/1/
$('.button').on('mousedown', function(){
$(this).data("mouseDown", true);
});
$('.button').on('mouseup', function(){
$(this).removeData("mouseDown");
});
$('.button').on('focus', function(){
if (!$(this).data("mouseDown"))
$(this).trigger('click.click');
});
$(".button").on('click.click',evHandler);
Which I stole directly from this:
https://stackoverflow.com/a/9440580/264498
You could use a timeout which get's cleared and set. This would introduce a slight delay but ensures only the last event is triggered.
$(function() {
$('#field').on('click focus', function() {
debounce(function() {
// Your code goes here.
console.log('event');
});
});
});
var debounceTimeout;
function debounce(callback) {
clearTimeout(debounceTimeout);
debounceTimeout = setTimeout(callback, 500);
}
Here's the fiddle http://jsfiddle.net/APEdu/
UPDATE
To address a comment elsewhere about use of a global, you could make the doubleBounceTimeout a collection of timeouts with a key passed in the event handler. Or you could pass the same timeout to any methods handling the same event. This way you could use the same method to handle this for any number of inputs.
Live demo (click).
I'm just simply setting a flag to gate off the click when the element is clicked the first time (focus given). Then, if the element gets focus from tabbing, the flag is also removed so that the first click will work.
var $foo = $('#foo');
var flag = 0;
$foo.click(function() {
if (flag) {
flag = 0;
return false;
}
console.log('clicked');
});
$foo.focus(function() {
flag = 1;
console.log('focused');
});
$(document).keyup(function(e) {
if (e.which === 9) {
var $focused = $('input:focus');
if ($focused.is($foo)) {
flag = 0;
}
}
});
It seems to me that you don't actually need the click handler. It sounds like this event is attached to an element which when clicked gains focus and fires the focus handler. So clicking it is always going to fire your focus handler, so you only need the focus handler.
If this is not the case then unfortunately no, there is no easy way to achieve what you are asking. Adding/removing a class on focus and only firing the click when the class isn't present is about the only way I can think of.
I have it - 2 options
1 - bind the click handler to the element in the focus callback
2 - bind the focus and the click handler to a different class, and use the focus callback to add the click class and use blur to remove the click class
Thanks for the great discussion everybody. Seems like the debouncing solution from #jfriend00, and the mousedown solution from Chris Meyers, are both decent ways to handle it.
I thought some more, and also came up with this solution:
// add focus event
$myInput.focus(function() {
myHelper();
// while focus is active, add click event
setTimeout(function() {
$myInput.click(function() {
myHelper();
});
}, 500); // slight delay seems to be required
});
// when we lose focus, unbind click event
$myInput.blur(function() {
$myInput.off('click');
});
But seems like those others are slightly more elegant. I especially like Chris' because it doesn't involve dealing with the timing.
Thanks again!!
Improving on #Christopher Meyers solution.
Some intro: Before the click event fires, 2 events are preceding it, mousedown & mouseup, if the mousedown is fired, we know that probably the mouseup will fire.
Therefore we probably wouldn't like that the focus event handler would execute its action. One scenario in which the mouseup wouldn't fire is if the user starts clicking the button then drags the cursor away, for that we use the blur event.
let mousedown = false;
const onMousedown = () => {
mousedown = true;
};
const onMouseup = () => {
mousedown = false;
// perform action
};
const onFocus = () => {
if (mousedown) return;
// perform action
};
const onBlur = () => {
mousedown = false;
// perform action if wanted
};
The following events would be attached:
const events = [
{ type: 'focus', handler: onFocus },
{ type: 'blur', handler: onBlur },
{ type: 'mousedown', handler: onMousedown },
{ type: 'mouseup', handler: onMouseup }
];

How can I block the keyup() event for a second in jQuery?

I'm doing a form validation in jQuery that alerts something when a forbidden character like #$#% is input by user. The problem is, when a user enters those characters, he uses the SHIFT key, so there are two keyup's.
How can I prevent the second one from happening?
if (!regex.test(lastCharacter)
alert('forbidden character');
Thanks a lot
You can bind on the input event which emits when input is changed, however this is only supported since IE9. Before that you can bind on the propertychange event (in IE only that is) which occurs when the value of an input changes. The example below will work in most browser also it might trigger the callback twice in IE9 so might need to check for input event support and act accordingly instead.
http://jsfiddle.net/X4qNf/
My bad here is the one with propertychange in it, try in IE if it doesn't work you might have to assign it the old way.
$('#boo')[0].onpropertychange = function() {};
http://jsfiddle.net/X4qNf/2/
I have no idea if this will work, but you get the idea:
$("#myInput").keyup(function(e) {
if(e.which == 16) {
$(this).keyup(function(event) {
if(event.which==16) event.preventDefault();
});
setTimeout(function() {
$("#myInput").off('keyup');
},1000);
}
});​

Capture "done" button click in iPhone's virtual keyboard with JavaScript

I'm wondering if there's a way to capture the iPhone's virtual keyboard's done button event, using JavaScript?
Basically, I just want to be able to call a JS function when the user clicks done.
I was unable to track the 'done' button being clicked. It didn't register any clicks or keypresses. I had to addEventListeners for change, focusout and blur using jquery (because the project already was using jquery).
You need to do some kind of this:
$('someElem').focusout(function(e) {
alert("Done key Pressed!!!!")
});
It worked for me, hope it will help you as well.
After searching and trying this solution
basically is say:
document.addEventListener('focusout', e => {});
tested on IPhone 6s
This question is kinda old, but I've found a hacky way recently to make this working.
The problem with the 'blur', 'focusout' events is that they fire even if user just tapped outside the input/textarea, and did not press the 'Done' button, in my case, UI should behave differently depending on what exactly have happened.
So to implement it, I've done the next thing:
After showing the keyboard (the input received the focus), add click handler on the window via the addEventListener function. When user clicks on the window, remember the timestamp of the click in the variable (let's call it lastClick = Date.now())
In the blur event handler, set a timeout for 10-20 ms to allow other events happening. Then, after the timeout, check if the blur event happened in a time difference lower for example than 50-100 ms than the lastClick (basically Date.now() - lastClick < 50). If yes, then consider it as a 'Done' button click and do corresponding logic. Otherwise, this is a regular 'blur' event.
The key here is that tapping on keyboard controls (including Done button) does not trigger the click event on the window. And the only other way to make keyboard hide is basically tap on other element of the page and make the textarea lose focus. So by checking when the event happened, we can estimate whether that's a done button click or just blur event.
The answer by oron tech using an event listener is the only one that works cross platform.
document.getElementById("myID").addEventListener("focusout", blurFunction);
function blurFunction() { // Do whatever you want, such as run another function
const myValue = document.getElementById("myID").value;
myOtherfunction(myValue);
}
"Change" event works fine
document.querySelector('your-input').addEventListener('change',e=>
console.log('Done button was clicked')
);
attach a blur event to the text box in question. The done fire will fire this event.
The done key is the same as the enter key. So you can listen to a keypress event. I'm writing this using jQuery and i use it in coffee script so I'm trying to convert it back to js in my head. Sorry if there is an error.
$('someElem').bind("keypress", function(e){
// enter key code is 13
if(e.which === 13){
console.log("user pressed done");
}
})

Categories

Resources