Setting priorities on HTML Events - javascript

We have a Web system that uses a combination of OnBlur and OnMouseDown events. Unfortunately, for a strange reason the OnMouseDown event handler is being triggered before calling the OnBlur event handler.
This is not what we want. Instead, we want to always call the OnBlur event handler prior to calling the onMouseDown event handler. Is there a way to do so, perhaps giving the onBlur a higher priority?
Previously, instead of using the onMouseDown event handler we had the onclick event. However, this posed a number of problems especially due to the single-threaded nature of JavaScript.

Catch event #2, fire event #1. Then let event #2 go through.
.. Catch-and-release pattern :)

You'll have to fake it by using a status variable. It's a bit dirty, but it works: the meat of doImportantStuff will only be run once.
var importantStuffDone = false;
function doImportantStuff(){
if(!importantStuffDone){
// Do something important
importantStuffDone = true;
}
}
function doOnBlur(){
// This function gets bound to the blur event
doImportantStuff();
// Do other blur stuff
}
function doOnMouseDown(){
// This function gets bound to the mousedown event
doImportantStuff();
// Do other mousedown stuff
}

Related

Is `blur` event dispatched by `pointerdown` guaranteed to fire before a user-scheduled task?

Let's say I have a button with a pointerdown (or mousedown) event handler, in which I schedule a task via setTimeout (irrespective of the delay).
Is the task guaranteed to execute after the blur event that fires as a consequence of the pointerdown event?
I've skimmed UI Events and Pointer Events specs but that didn't help me.
My understanding is that the blur event is just another task being scheduled on the event loop before the pointerdown event handler is invoked, and as such, it's virtually guaranteed that any user-scheduled tasks will fire after the blur event fires.
Note that by "blur event firing" I mean both the native browser behavior that happens on a blur event (such as de-focusing inputs), and user-registered event handlers on that blur event. See below example:
window.btn.addEventListener("pointerdown", () => {
window.txt.onblur = null;
setTimeout(() => { // this should be invoked *after* the `blur` event
window.txt.onblur = () => { // this should never run when clicking on the button
console.log("blurred");
};
window.txt.focus();
});
});
<textarea id="txt"></textarea>
<button id="btn">focus</button>
It feels like the answer will be "it's up to the user agent (browser)".
In your example code you simply remove the onblur handler for the text field and immediately re-add a new handler.
Whether the blur event (and its handlers) of the input field or the pointerdown event (and its handlers) is pushed onto the event loop probably depends on the browser implementation, since this edge case might not be specified.

Are methods considered event handlers?

I'm studying javascript and jquery am a little confused on the proper definition of an event handler.
So far I've read .on() (for example ) is technically a method but it is handling events. So would .on() be considered an event handler? Or is it an event listener because the function inside of it is the handler?
No. jQuery's on is a method which adds event listeners. It's not an event handler and does not add event handlers.
An event listener is a function that is invoked when a certain kind of event is dispatched on a specific element or one of its descendants.
function eventListener() {
console.log("I'm an event listener");
}
window.addEventListener('load', eventListener);
An event handler is some kind of special event listener:
An element can only have one event handler at a time for each kind of event
It is invoked during the bubble phase, not the capture one.
It can be stored in a raw uncompiled form which, when compiled, will run with a very weird scope.
function eventHandler() {
console.log("I'm an event handler");
}
window.onload = eventHandler;
var eventHandler = 'console.log("I\'m a raw uncompiled event handler");';
document.body.setAttribute('onload', eventHandler);
No, an event handler is what happens when the event fires. The .on() method is the plumbing that wires that up.
So for example, if you have:
function dealWithTheClick(){
alert('Clicked!');
}
$('#someButton').on('click', dealWithTheClick);
The function dealWithTheClick is the event handler, because it's the function that 'handles' the event that was fired when the click occurred.

Change the Attr and do new function not working in jQuery [duplicate]

I have a site that uses AJAX to navigate. I have two pages that I use a click and drag feature using:
$(".myDragArea").mousedown(function(){
do stuff...
mouseDrag = true; // mouseDrag is global.
});
$("body").mousemove(function(){
if (mouseDrag) {
do stuff...
}
});
$("body").mouseup(function(){
if (mouseDrag) {
do stuff...
mouseDrag = false;
}
});
I just type that out, so excuse any incidental syntax errors. Two parts of the site use almost identical code, with the only difference being what is inside the $("body").mouseup() function. However, if I access the first part, then navigate to the second part, the code that runs on mouseup doesn't change. I have stepped through the code with Firebug, and no errors or thrown when $("body").mouseup() is run when the second part loads.
So, why doesn't the event handler change when I run $("body").mouseup() the second time?
Using $("body").mouseup( ... ) will add an event handler for the body that is triggered at mouseup.
If you want to add another event handler that would conflict with current event handler(s) then you must first remove the current conflicting event handler(s).
You have 4 options to do this with .unbind(). I'll list them from the least precise to the most precise options:
Nuclear option - Remove all event handlers from the body
$("body").unbind();
This is pretty crude. Let's try to improve.
The elephant gun - Remove all mouseup event handlers from the body
$("body").unbind('mouseup');
This is a little better, but we can still be more precise.
The surgeon's scalpel - Remove one specific event handler from the body
$("body").unbind('mouseup', myMouseUpV1);
Of course for this version you must set a variable to your event handler. In your case this would look something like:
myMouseUpV1 = function(){
if (mouseDrag) {
do stuff...
mouseDrag = false;
}
}
$("body").mouseup(myMouseUpV1);
$("body").unbind('mouseup', myMouseUpV1);
$("body").mouseup(myMouseUpV2); // where you've defined V2 somewhere
Scalpel with anesthesia (ok, the analogy's wearing thin) - You can create namespaces for the event handlers you bind and unbind. You can use this technique to bind and unbind either anonymous functions or references to functions. For namespaces, you have to use the .bind() method directly instead of one of the shortcuts ( like .mouseover() ).
To create a namespace:
$("body").bind('mouseup.mySpace', function() { ... });
or
$("body").bind('mouseup.mySpace', myHandler);
Then to unbind either of the previous examples, you would use:
$("body").unbind('mouseup.mySpace');
You can unbind multiple namespaced handlers at once by chaining them:
$("body").unbind('mouseup.mySpace1.mySpace2.yourSpace');
Finally, you can unbind all event handlers in a namespace irrespective of the event type!
$("body").unbind('.mySpace')
You cannot do this with a simple reference to a handler. $("body").unbind(myHandler) will not work, since with a simple reference to a handler you must specify the event type ( $("body").unbind('mouseup', myHandler) )!
PS: You can also unbind an event from within itself using .unbind(event). This could be useful if you want to trigger an event handler only a limited number of times.
var timesClicked = 0;
$('input').bind('click', function(event) {
alert('Moar Cheezburgerz!');
timesClicked++;
if (timesClicked >= 2) {
$('input').unbind(event);
$('input').val("NO MOAR!");
}
});​
Calling $("body").mouseup(function) will add an event handler.
You need to remove the existing handler by writing $("body").unbind('mouseup');.
jQUery doesn't "replace" event handlers when you wire up handlers.
If you're using Ajax to navigate, and not refreshing the overall DOM (i.e. not creating an entirely new body element on each request), then executing a new line like:
$("body").mouseup(function(){
is just going to add an additional handler. Your first handler will still exist.
You'll need to specifically remove any handlers by calling
$("body").unbind("mouseUp");

Programmatically call "mousemove" event in JS

Is there a possibility to programmatically call the mousemove event in jQuery?
Obviously, I'm not going to change the actual position of the cursor - it's impossible. All I want is re-call this event so all other scripts that have attached their handers to it will also be called.
To trigger event handlers bound to the mousemove event you can use trigger()
$('#elementID').on('mousemove', function() {
// do stuff
});
$('#elementID').trigger('mousemove'); // triggers above event handler

What's the cross-browser way to capture all single clicks on a button?

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.

Categories

Resources