Whenever a blur event is triggered from any input element, I want to set focus to one particular element.
This issue arises when I am trying to focus to the same element triggering the blur event.
Why does this only works, when the element I am trying to focus on to, is not the one triggering the event?
[Issue Illustration]
and explanation as per the fiddle:
The element I am trying to focus to is col0
Unless the element to trigger the blur event is not col0 it works perfect
But when blur is triggered from col0 itself, then $("#col0").focus() does not work.
Q: Why? & What is the workaround/solution?
P.S: I am just trying to know the cause of the behavior and ways to overcome it. Concerns about the usability, is NOT THE QUESTION.
This works in FF for me...
$('input').on('blur', function() {
setTimeout(function () { $("#col0").focus(); }, 0);
});
it is just to postpone a UI action a bit (after processing the blur event is finished).
Warning: in jsfiddle FF won't let you edit the code after you try it, once you get to the input you are stuck there until refresh
Update: The explanation is tricky, as it is a matter of implementation in FF (as Chrome and IE behave as you expected), my guess is that FF prevents firing related events when you are in the event handler for the same element (a thing that may potentially lead to infinite cycle), using setTimeout you are firing the event soon after you leave the handler (and even UI has a chance to redraw itself)
It looks like you're trying to keep focus on everything except the control you're on. Try this:
$('input:not(#idofcontrol)').blur(function() {
$('#idofcontrol').focus();
});
Related
I've written an html5 application which is supposed to work on mobile devices. 90% of the time it works fine however in certain devices (mostly androids 4.0+) the click events fire twice.
I know why that happens, I'm using iScroll 4 to simulate native scrolling and it handles the events that happen inside the scroll.(line 533 dispatches the event if you're interested) Most of the time it works fine but in certain devices both the iScroll dispatched event and the original onClick event attached to the element are fired, so the click happens twice. I can't find a pattern on which devices this happen so I'm looking for alternatives to prevent double clicks.
I already came up with an ugly fix that solves the problem. I've wrapped all the clicks in a "handleClick" method, that is not allowed to run more often than 200ms. That became really tough to maintain. If I have dynamically generated content it becomes a huge mess and it gets worse when I try to pass objects as parameters.
var preventClick = false;
function handleClick(myFunction){
if (preventClick)
return;
setTimeout(function(){preventClick = true;},200);
myFunction.call():
}
function myFunction(){
...
}
<div onclick='handleClick(myfunction)'> click me </div>
I've been trying to find a way to intercept all click events in the whole page, and there somehow work out if the event should be fired or not. Is it possible to do something like that?
Set myFunction on click but before it's called, trigger handleClick()? I'm playing with custom events at the moment, it's looking promising but I'd like to not have to change every event in the whole application.
<div onclick='myfunction()'> click me </div>
You can do that with the following ( i wouldn't recommend it though):
$('body').on('click', function(event){
event.preventDefault();
// your code to handle the clicks
});
This will prevent the default functionality of clicks in your browser, if you want to know the target of the click just use event.target.
Refer to this answer for an idea on how to add a click check before the preventDefault();
I don't like events on attributes, but that's just me.
Thinking jquery: $(selector).click(function(){ <your handler code> } you could do something like:
$(selector).click(function(event){
handleClick(window[$(this).attr("onclick")]);
};
of course, there wouldn't be any parameters...
I have a <select id="myselect" name="myselect" onChange="(myfunction();)">...</select> which works perfect in IE and Opera. The word "perfect" means the event fired when you change the values from the drop-list by mouse or by any of "Up", "Down", "PageUp"(not for Opera), "PageDown"(not for Opera), "Home" and "End" keys when select menu is active (blue). The problem appears when you test it using Firefox, 3.6.Xv. Nothing happens when you use "Up" and "Down", but for mouse it still works.
Do you recommend to use onkeyup event? I've tried it, it "catches" up and down, but, IE appears to have both onChange and onkeyup event. But I need just one event.
How do people solve this issue?
Thank you.
I recommend that you keep using the change event. The Firefox implementation makes lots of sense for keyboard users. If you tab to the select element and choose an entry using Up and Down keys (and you have to press them a lot for a lengthy list) you don't want to trigger tons of actions on the web page. It is ok to have the action executed once you've selected the correct entry and moved on to something else.
This is a pretty dirty hack, but you can force the the change event to fire by doing this:
element.addEventListener('keyup', function(evt){
evt.target.blur();
evt.target.focus();
}, false);
So you'd register an event listener for change as well, and that function would get called when the user presses a key on the <select> via the code above.
You may want to scope this only to Firefox, but AFAIK you'd have to use UA sniffing for that so it's up to you if that's acceptable.
Source
You could be clever and make your own handler for the keyup event which tests the keycode to see if it was an up arrow or down arrow, and fires the change event accordingly.
My own js isn't good enough to write you an example but I could show some example jQuery to do that:
$('yourSelect').keyup(function(e)
{
if (e.keyCode===38)
{
//this is an up arrow press
//trigger the change event
$('yourSelect').change();
}
else if (e.keyCode===40)
{
//down arrow has pressed
//trigger the change event
$('yourSelect').change();
}
});
This question comes with a bit of background. Please see two other questions I've recently posted that relate:
How to select text in a textbox cross-browser
Infinite loops created in google chrome
Word of warning: it's possible that the second link is a red herring.
Ok so my problem is that I'm trying to have it so when a user first clicks or tabs in to a textbox, all the text should become selected. If the textbox has focus, subsequent clicks on the text inside the textbox should behave normally (ie. doesn't re-select all the text). The answer I choose in the first link above is the one I found worked across all browsers. Code posted below for your convenience:
$('input[type="text"]').live('focus', function (event) {
var inp = this;
setTimeout(function () {
inp.select();
}, 1);
event.stopPropagation();
event.preventDefault();
return false;
});
Now my second link above is what I seem to be running in to with this approach. It seems that intermittently, google chrome gets stuck somewhere and starts changing the focus between textboxes really fast. You can see what I think is happening here: http://jsfiddle.net/ajbeaven/XppG9/14/
Like I said, it seems to be an intermittent problem so you might have to try reloading the page a couple of times in order to see what I think might be causing the changing of focus. Remember, it only seems to happen in chrome.
Thanks to anyone who can shed some light!
Put any additional work in the setTimeout function. And add a clearTimeout() before you setTimeout():
var focusTimeout = 0;
$('input[type="text"]').live('focus', function(event) {
var inp = this;
clearTimeout(focusTimeout);
focusTimeout = setTimeout(function() {
$('#message-container').html($('#message-container').html() + "*\u200b");
inp.select();
}, 1);
});
http://jsfiddle.net/XppG9/19/
In Chrome, writing the html to the page is (apparantly) causing the field to lose focus, and select() is causing it to receive focus 1ms later, thus triggering the focus event and causing the infinite loop. Moving the write html call into the function that selects the text seems to do the trick.
Oh man, I just figured it out. This bug probably won't happen to you on a real website. It's happening because you are updating the DOM adding a "*" to the message div. When you do this, it pushes the content of the page down. This moves the top text box to where the mouse is, and the mouseup event is triggered on the top text box, causing both text boxes to fire a setTimeout and getting in an infinite loop. Total dibs on reporting this.
edit: it's probably not the mouseup event. looks like chrome thinks you are legit focusing on both. Here's the bug test case for Chrome: http://jsfiddle.net/delvarworld/AnBE8/
edit2: This happens in Safari too. Most likely a webkit issue.
tldr simple workaround is to not update the dom in a way that causes reflow on the focus event, as in get rid of the html() line
You could also try:
$('input[type="text"]').live('mouseup', function (event) {
Which works in Chrome for me
I have some javascript click handlers that don't do what I want in IE8. What I want to do is call a handler on the first click and then call another handler on all subsequent clicks. The way I do that is put the original handler in the onclick attribute and then use that handler to erase the onclick attribute and use Event#observe to set up the handler that is called on subsequent clicks but for some reason IE8 refuses to cooperate. Instead of the following program flow
click->call originalHandler->erase originalHandler->set newHandler
I get the unexpected program flow
click->call originalHandler->erase originalHandler->set newHandler->call newHandler
I can't figure out why a single click event fires both handlers. Here's the snippet of the offending code, the pastie link and a link to a page that consistently reproduces the bug on my laptop with ie8.
//weird behavior in the latest prototype version with ie8
function originalHandler(event) {
Event.stop(event); //this doesn't help either, the event still triggers newHandler
var button = $('button');
alert("first click");
button.writeAttribute({onclick:null});
function newHandler(event) {
//this should only show up on the second click
//but it shows up on the first click as well
alert('second click');
}
button.observe('click',newHandler);
}
So to get the desired behavior I have to add an extra layer of indirection which seems really weird. So the following code fixes the issue with IE8 but breaks firefox and chrome behavior because now "second click" doesn't show up until the third click. Here's the pastie for the version that works on IE8 and the link to the page that behaves correctly on IE8 but requires an extra click on chrome and firefox.
function originalHandler(event) {
Event.stop(event);
var button = $('button');
alert("first click");
button.writeAttribute({onclick:null});
var newHandler = function(ev) {
button.stopObserving();
button.observe('click',function() {alert("second click");});
}
button.observe('click',newHandler);
}
Any ideas on how to fix this bug and get consistent behavior across all browsers?
I also asked on the prototype mailing list and the answer I got was that basically what's happening is that IE8 calls the DOM0 handler and then calls DOM2 handlers which is what I set up with Element#observe and the way around it is to set up a delay so that the DOM2 handler is not set up until the first event bubbles all the way up without any DOM2 handlers in the way. Oh how I hate cross-browser compatibility.
What's the best way to execute a function exactly once every time a button is clicked, regardless of click speed and browser?
Simply binding a "click" handler works perfectly in all browsers except IE.
In IE, when the user clicks too fast, only "dblclick" fires, so the "click" handler is never executed. Other browsers trigger both events so it's not a problem for them.
The obvious solution/hack (to me at least) is to attach a dblclick handler in IE that triggers my click handler twice. Another idea is to track clicks myself with mousedown/mouseup, which seems pretty primitive and probably belongs in a framework rather than my application.
So, what's the best/usual/right way of handling this? (pure Javascript or jQuery preferred)
Depending on your situation you can use different approaches, but I would suggest using namespaced event handlers with jQuery like this:
function eventHandler(event) {
// your handler code here
doSomeMagic();
}
var element = $('#element');
element.one('click.someNameSpace', function(event){
// first we unbind all other event handlers with this namespace
element.unbind('.someNameSpace');
// then we execute our eventHandler
eventHandler();
}).one('dblclick.someNameSpace', function(event){
// If this fires first, we also unbind all event handlers
element.unbind('.someNameSpace');
// and then execute our eventHandler
eventHandler();
});
I'm not sure this will work the way you want it, but it's a start, I guess.
Mousedown and mouseup works just like the click functions, unfortunately so much that when IE omits a click because of a doubleclick it will also omit the mousedown and mouseup. In any case, you can add both click and dblclick to the same object and feed the clicks through a function that sort out any click happening too close to the last.
<div onclick="clk()" ondblclick="clk()"></div>
lastclicktime=0
function clk(){
var time=new Date().getTime()
if(time>lastclicktime+50){
lastclicktime=time
//Handle click
}
}
I by the way just found out that, at least in Firefox the dblclick event is not given an event time, therefore I had to resolve to the Date method.