JavaScript event handler race - javascript

If I have a text field with a registered onblur event handler and a button with a registered onmouseup event handler, which one of those two functions will run sooner and why?
To make my question clearer, let's suppose the focus is currently on the text field and I want to click on the button.
Will there be any difference between various Internet browsers?
Edit
Especially tricky seems the onmousedown event when it's registered with the button, whilst the text field has an onblur event registered with it.

The spec says blur must be fired when focus leaves the element (after taking focus away), but I don't see any explicit statement about when that must occur relative to the event causing the focus to be moved away.
Certainly the mouseup will happen much later (in computer terms), as first you have to mousedown.
I would have expected blur to fire prior to even the mousedown, but I would have been wrong: According to experimentation, mouseup is after, but mousedown is before. I tested that using Chrome 26, Opera 12.15, Firefox 20, IE8, and IE9 — and if you can get those five to agree on a behavior, it's likely to be consistent in others... :-) My suspicion is that this is because if you prevent the default action of the mousedown, focus never moves away from the text field: Example. (This behavior is consistent across four of those five browsers, with IE8 not preventing the focus change — meaning IE7 and 6 probably don't, either.) So while it seems odd, it does kind of make sense.
As always, test with the browsers you intend to support.

Just save the timestamp when starting
var start = new Date().getTime();
and then
var elapsed = new Date().getTime() - start;
into the handler.

Related

Element focus listener not triggered after first element.focus()

I've noticed a rather odd behavior when running a unit test which passed on PhantomJS but occasionally failed in Chrome, Firefox and IE. In a nutshell:
I set a focus listener for a DOM element.
I invoked element.focus(), yet the listener was not run.
Calling element.focus() for a second time actually ran the listener.
Unfortunately I couldn't reproduce this issue in a fiddle, but it can be done, for instance, in jQuery's website. I do the following steps on Chrome:
Open www.jquery.com and then open DevTools.
Run $("input[name=s]").on("focus", () => console.log("a"));.
Run $("input[name=s]").focus();. No output is generated.
Run $("input[name=s]").focus();. Now "a" is printed to the console for the first time!
What is causing this issue and how could I work around it?
Had a quick delve around the jquery source code, and it seems that focus actually uses focusin, and the code is trying to map to focusin. so if you try this:
$("input[name=s]").on("focusin", () => console.log("a"));
$("input[name=s]").focusin();
it will work. There is a difference between focus and focusin around bubbling:
http://api.jquery.com/focusin/
The focusin event is sent to an element when it, or any element inside
of it, gains focus. This is distinct from the focus event in that it
supports detecting the focus event on parent elements (in other words,
it supports event bubbling).
It seems like the behaviour is a hard to replicate bug, that must be caused by other bit of code somewhere (maybe a lib). Although the code above should help work around it.

IE8 addEventListener on change event not working on first click

I have a site which has three radio inputs and based on which input is selected parts of the html page around it will change. Everything works perfect except in IE8(of course). My issue for this page is that when I click on the input which has an event listener of 'change' on it, nothing will happen, it is only until it is clicked the second time that the event will fire. I know that IE8 doesnt handle addEventListeners but I am using a pollyfill for all this and am using addEventListeners for tons of other things on the site and they work fine.
The second thing to note is that everything works fine in IE8 if I switch the event listener to a 'click' event. The only issue and reason why im not just switching it to 'click' is because of tabbing. I still what the user to still be able to tab through the form for a proper UX.
Lastly when I bring the site up in my VB for IE8, this functionality(even with the 'click' event) will not work until I put it in debugging mode and it finds all the polyfill.min.js errors. Then I can stop debugging and everything will then work as intended. I will provide a picture of my errors. I have no idea why and what is causing them. My guess would be some external script I am pull for third party functionality maybe. Cant figure that out yet.
here is how the function is being called,
Here is where the function is called:
function attachToggleReportType (elem) {
console.log('Trigger attachToggleReportType');
elem.addEventListener('change', toggleReportType, false);
}
And here is the main function for the actions to happen based on the event
function toggleReportType () {
console.log('Trigger toggleReportType');
var reportOptions = document.querySelectorAll('.report'),
reportIncToggle = document.querySelectorAll('.toggle');
console.log(this.getAttribute('data-sample-report-link'));
reportSample({
href: this.getAttribute('data-sample-report-link'),
src: this.getAttribute('data-sample-report-image'),
title: this.getAttribute('data-sample-report-title')
});
reportIncToggle.forEach(toggleInclude);
}
So I found a solution for my problem. It is not perfect but it worked fine for me, for now. It was a pretty odd issue because in IE8 my event listener with a type of 'change' would always have a click delay on it. So no matter which radio I would click, the only time the event would fire is when I clicked again anywhere on the screen the second time. I know IE8 doesnt handle addEventListeners but I was using a polyfill for accommodate this. I also would get a polyfill error when in debug mode, so I wonder if this is an issue related to that. Anyways, i resolved this issue for now by including a 'change' event listen for modern browsers, then in IE8 i switched it to an on 'focus' event and everything works perfectly still. I hate the idea of having two event types but it was the only way to resolve this bug. Also to note, the change event still worked in IE8 on the second click, so trying to detect if the browser could handle this event type wasn't an option for me.

Synchronizing identical html forms

I'd like to have two (or even more) identical html forms on my website.
For example, one - at the top, and another - at the bottom of the page.
What i want is for them to have exactly the same content at any given time. If user changes a value in one of them, all the rest are updated.
Is there a better way to synchronize then javascript onchange/onkeyup events?
onchange fires only after element loses focus.
onkeyup is not perfect too. It wastes a lot of cpu on long text copying and won't fire if element lost focus between onkeydown and onkeyup events.
Update: I just learned that HTML5 has a more appropriate event for this, oninput, but of course it doesn't work in older browsers. oninput will detect any kind of text change, including Paste, Cut, and Delete from the right-click menu. So the best option may be to check if the browser supports oninput (e.g. by using the function recommended here), falling back to the below method if not. On older versions of IE, onpropertychange can be used to simulate oninput.
I decided to change my answer, based on how KnockoutJS accomplishes this. From this page in the Knockout docs:
"afterkeydown" - updates your view model as soon as the user begins typing a
character. This works by catching the browser’s keydown event and handling the event
asynchronously.
Of these options, "afterkeydown" is the best choice if you want to keep your view model
updated in real-time.
It accomplishes the asynchronous behavior by using setTimeout with a time value of zero. Other than that, it appears to be just like a regular keydown event handler.
Here's a simple example, using jQuery, which I believe behaves equivalently to Knockout's "afterkeydown" event:
$('#email').keydown(function() {
setTimeout( $.proxy(handler, this), 0);
});
function handler() {
console.log( this.value );
}
Note:
This will not catch right-click paste events and drag-and-drop events. If you want to update the text on those events too, simply listen for them in the same manner as keydown, e.g.:
$('#email').on('keydown paste drop', function() {
setTimeout( $.proxy(handler, this), 0);
});
Like keydown, paste and drop also need the setTimeout in order to update with the latest value of the text.
Original answer:
onkeyup is probably the way to go, but you raise a good point about it not firing if the element loses focus between keydown and keyup. Based on this answer, I'm pretty sure the solution would be to listen for the keyup event on a container element (or on the body, although in this case it would probably make the most sense to bind it to the <form> element).
As to CPU usage on paste, you could try canceling the event unless a certain amount of time has passed (say 50 ms)...hopefully that will be sufficient. If not, you could look at how some of the popular 2-way data-binding frameworks handle this...most of the ones I've seen use onkeyup.

Issues with using onBlur event

I have taken a look around Stack Overflow on the topic of onblur but so far have not been able to locate an approach to solve what I want to do.
What I have is a simple two column tables with an unknown number of rows. Rows are created at render time based on the number of boxes being shipped. Each column has the following name and id for the input box:
For column 1: shipItems[ rowNum ].barcode
For column 2: shipItems[ rowNum ].trackingcode
Pretty straight forward. What I want to do is validate the trackingcode and if in error alert the user and re-focus the cursor on the column/row that caused the problem. Users will be using a scanner to scan in the information.
Every things works except that I can not get the cursor to go back to the column/input that caused the issue in the onBlur event.
My understanding is that when the onBlur event fires the element is losing focus and thus the focus is being transferred to the new/next element.
I have tried to playing around with the onfocus event, onkeypress events but still have not been successful.
I am open to any ideal to get this done, I have spend way to much time on it as it is. JQuery is not out of the questions or just plan old Javascript.
UPDATE
Here is a link to the script on jsFiddle:
After reviewing your code, best I can tell you are experiencing an unusual bug in jQuery. I have seen some quirky things happen when using focus() (like having to use setTimeout). But, in your case the $(this) is somehow not resolving correctly when calling focus().
At first I thought it was because the id is not following HTML-4 standards, but correcting the id did not help. $(this) still failed to focus, despite the fact it correctly refers to the <input> element. Then I tried identifying the id with jQuery as a string $("'#" + thisId + "'")...still did not work. But, a hard coded id did work...
So, here's how I modified your code and worked around the problem to get it to focus
if( null === $text.match(/\b(1Z ?[0-9A-Z]{3} ?[0-9A-Z]{3} ?[0-9A-Z]{2} ?[0-9A-Z]{4} ?[0-9A-Z]{3} ?[0-9A-Z]|[\dT]\d\d\d ?\d\d\d\d ?\d\d\d)\b/))
{
alert("No Match");
//$(this).focus();//don't use jquery $this
var thisId = $(this).attr('id');//get the id
//use the setTimeout workaround for firefox
setTimeout(function() {
document.getElementById(thisId).focus();//use javascript to set focus
},0);
$(this).css('background-color','Red');
}
Feel free to look at the fiddle (linked above). This approach does correct the focus problem.
I figured out the issue. It turns out that IE and FireFox have very different behavior when it comes to onBlur.
I was calling focus() during the execution of the blur(). since the blur has not completed it either ignored the focus command or executes and then completes the blur.
Some browsers the focus command can cause a blur to be triggered thus creating an infinite loop with the cursor bouncing between the two fields.
Using a timeout will cause the focus to trigger outside of the blur call back function.
Under IE I can make use of onBlur and have no issues, under FF the focus never got called event with a timeout, so it needs an onChange.
I have updated my script - it runs fine on IE - http://jsfiddle.net/boyd4715/3wbtQ/34/

JavaScript event for contenteditable elements

Is there a way to capture JavaScript events for when a contenteditable element begins and ends editing?
I'm not sure exactly here, but aren't you after focus and blur? I'm not sure what else "begins and ends editing" could be translated to that has a different timing than those, unless you mean an event for every keystroke, etc.
As Nick said, focus and blur will work, and in all major browsers. IE also has a number of related events (although none of these are implemented in other browsers as far as I know): activate, deactivate, beforeactivate, beforedeactivate and beforeeditfocus

Categories