Detect browser autoclick - javascript

I have some problems in implementing my jQuery plugin.
I need a plugin which shows me some element (popup) and hides it when i click out of bounds of this element.
I implemented this plugin. But I have problems with forms in popup. When I calculate coordinates of clicked element I use pageX and pageY properties.
But it is some interesting things when I try to submit form using ENTER key. When I push ENTER browser triggered 'click' event on submit button, but pageX and pageY of this button is equal 0. In event.target I see my button.
When I click submit button myself - everything is OK.
Question: how can I detect who clicked this button? User or browser? (without any spikes like detecting enter key on input or so on)
Additional: as you can see here events are different (when click on submit and press ENTER). But difference is so small... I see only that 'detail' property is set to 0, when we submit form by ENTER.
Detail property is amount of clicks on element for mouse event.
Is it only way to detect submission? Is it correct?

If you're binding a click handler to a click event and later calling the click programmatically as well as from a user click and want to differentiate the two events in the handler, you can check for eventObject.originalEvent which is set in the user click but not the .click() call.
Example:
$('#el').click(function(evt){ if(evt.originalEvent){ //user click } else { // .click() call } });

How about testing for pageX == 0 AND pageY == 0?
Or even better, assuming it is a form (it implies from your post), why not use .submit() rather then .click()?

Related

Javascript: on blur getting the event's relatedTarget on mobile safari

So, I have a form with custom validation that is triggered on input blur event...
works fine
the form submit prevents the form to be submitted if there are validation errors on the page...
effectively what that means is if there is an erroneous message and it's focused.... if you click submit button, first the element's blur is triggered and the submit... but coz the element is
in practice I would have to click submit twice.... first time to re-validate the element and second to trigger submit again...(when all the elements are valid)
so on blur, I do
if ( event.relatedTarget && event.relatedTarget.type === "submit" ) {
...
}
and check if the instigator (of element's blur event) is the submit button...if yes, I skip the validation and trigger submit directly.... (that handles validation itself)..
It works perfectly, even in OSX...
the problem is mobile safari... that simply doesn't populate the event.relatedTarget... (is always null on submit click.... it's populated only on some other element's focus)....
how can I get the instigator on iOS?
I had the same problem where I had to hit the submit button on my form twice (on iOS.) Surprisingly I found that this solution worked:
how to prevent blur running
It was not clear at first but using this solution the mousedown event stops my normal blur event from happening but if you click the "Done" on the iOS keyboard it will let the blur event run because there was no mousedown event.

Focusing a Bootstrap button for keyboard enter

I have a Bootstrap 3.0 button on a web page. The button is not part of a form. When this page renders, I would like for the button to be clicked if the user hits return on the keyboard. I have a Marionette event listener set up to handle the click event.
Here is my button:
<button class="btn btn-primary js-new pull-right">New facility</button>
How do I do this?
I have tried several things - including what I thought was the obvious solution: executing $(".js-new").first().focus(). This does not work.
If I understand correctly, you'd like to trigger the click handler for a certain button when "return" is hit. If that's the case, this ought to work; $(".js-new").first().click();, assuming your selector is correct.
You can check whether or not your selector is finding an element by using either alert or console.log to display the length of the selector: console.log($(".js-new").length);.
Once you have verified that you have found the correct element, you can trigger whatever click handler(s) are bound to the element by simply calling the .click() function; if no arguments are passed to it, it executes whatever triggers are already on the element.
--
Edit: if you'd simply like to trigger the click handler when enter is pressed, you could bind an event to the return key:
$(document).keypress(function(e) {
if(e.which === 13) {
// enter has been pressed, execute a click on .js-new:
$(".js-new").first().click();
}
});

Blur event stops click event from working?

It appears that the Blur event stops the click event handler from working? I have a combo box where the options only appear when the text field has focus. Choosing an option link should cause an event to occur.
I have a fiddle example here: http://jsfiddle.net/uXq5p/6/
To reproduce:
Select the text box
Links appear
Click a link
The blur even occurs and the links disappear
Nothing else happens.
Expected behavior:
On step 5, after blur occurs, the click even should also then fire. How do I make that happen?
UPDATE:
After playing with this for a while, it seems that someone has gone to great lengths to prevent an already-occurred click event from being handled if a blur event makes the clicked element Un-clickable.
For example:
$('#ShippingGroupListWrapper').css('left','-20px');
works just fine, but
$('#ShippingGroupListWrapper').css('left','-2000px');
prevents the click event.
This appears to be a bug in Firefox, since making an element un-clickable should prevent future clicks, but not cancel ones that have already occurred when it could be clicked.
Other things that prevent the click event from processing:
$('#ShippingGroupListWrapper').css('z-index','-20');
$('#ShippingGroupListWrapper').css('display','none');
$('#ShippingGroupListWrapper').css('visibility','hidden');
$('#ShippingGroupListWrapper').css('opacity','.5');
I've found a few other questions on this site that are having similar problems. There seem to be two solutions floating around:
Use a delay. This is bad because it creates a race condition between the hiding and the click event handler. Its also sloppy.
Use the mousedown event. But this isn't a great solution either since click is the correct event for a link. The behavior of mousedown is counter-intuitive from a UX perspective, particularly since you can't cancel the click by moving the mouse off the element before releasing the button.
I can think of a few more.
3.Use mouseover and mouseout on the link to enable/disable the blur event for the field. This doesn't work with keyboard tabing since the mouse is not involved.
4.The best solution would be something like:
$('#ShippingGroup').blur(function()
{
if($(document.activeElement) == $('.ShippingGroupLinkList'))
return; // The element that now has focus is a link, do nothing
$('#ShippingGroupListWrapper').css('display','none'); // hide it.
}
Unfortunately, $(document.activeElement) seems to always return the body element, not the one that was clicked. But maybe if there was a reliable way to know either 1. which element now has focus or two, which element caused the blur (not which element is blurring) from within the blur handler. Also, is there any other event (besides mousedown) that fires before blur?
click event triggers after the blur so the link gets hidden. Instead of click use mousedown it will work.
$('.ShippingGroupLinkList').live("mousedown", function(e) {
alert('You wont see me if your cursor was in the text box');
});
Other alternative is to have some delay before you hide the links on blur event. Its upto you which approach to go for.
Demo
You could try the mousedown event instead of click.
$('.ShippingGroupLinkList').live("mousedown", function(e) {
alert('You wont see me if your cursor was in the text box');
});
This is clearly not the best solution as a mousedown event is not achieved the same way for the user than a click event. Unfortunately, the blur event will cancel out mouseup events as well.
Performing an action that should happen on a click on a mousedown is bad UX. Instead, what's a click effectively made up of? A mousedown and a mouseup.
Therefore, stop the propagation of the mousedown event in the mousedown handler, and perform the action in the mouseup handler.
An example in ReactJS:
<a onMouseDown={e => e.preventDefault()}
onMouseUp={() => alert("CLICK")}>
Click me!
</a>
4.The best solution would be something like:
$('#ShippingGroup').blur(function()
{
if($(document.activeElement) == $('.ShippingGroupLinkList'))
return; // The element that now has focus is a link, do nothing
$('#ShippingGroupListWrapper').css('display','none'); // hide it.
}
Unfortunately, $(document.activeElement) seems to always return the
body element, not the one that was clicked. But maybe if there was a
reliable way to know either 1. which element now has focus or two,
which element caused the blur (not which element is blurring) from
within the blur handler.
What you may be looking for is e.relatedTarget. So when clicking the link, e.relatedTarget should get populated with the link element, so in your blur handler, you can choose not to hide the container if the element clicked is within the container (or compare it directly with the link):
$('#ShippingGroup').blur(function(e)
{
if(!e.relatedTarget || !e.currentTarget.contains(e.relatedTarget)) {
// Alt: (!e.relatedTarget || $(e.relatedTarget) == $('.ShippingGroupLinkList'))
$('#ShippingGroupListWrapper').css('display','none'); // hide it.
}
}
(relatedTarget may not be supported in older browsers for blur events, but it appears to work in latest Chrome, Firefox, and Safari)
If this.menuTarget.classList.add("hidden") is the blur behavior that hides the clickable menu, then I succeeded by waiting 100ms before invoking it.
setTimeout(() => {
this.menuTarget.classList.add()
}, 100)
This allowed the click event to be processed upon the menuTarget DOM before it was hidden.
I know this is a later reply, but I had this same issue, and a lot of these solutions didn't really work in my scenario. mousedown is not functional with forms, it can cause the enter key functionality to change on the submit button. Instead, you can set a variable _mouseclick true in the mousedown, check it in the blur, and preventDefault() if it's true. Then, in the mouseup set the variable false. I did not see issues with this, unless someone can think of any.
I have faced a similar issue while using jQuery blur, click handlers where I had an input name field and a Save button. Used blur event to populate name into a title placeholder. But when we click save immediately after typing the name, only the blur event gets fired and the save btn click event is disregarded.
The hack I used was to tap into the event object we get from blur event and check for event.relatedTarget.
PFB the code that worked for me:
$("#inputName").blur(function (event) {
title = event.target.value;
//since blur stops an immediate click event from firing - Firing click event here
if (event.relatedTarget ? event.relatedTarget.id == "btnSave" : false) {
saveBtn();
}
});
$("#btnSave").click(SaveBtn)
As already discussed in this thread - this is due to blur event blocking click event when fired simultaneously. So I have a click event registered for Save Btn calling a function which is also called when blur event's related Target is the Save button to compensate for the click event not firing.
Note: Didnt notice this issue while using native onclick and onblur handlers - tested in html.

DOM problem with click initiating a focusout event on a different input

I have an <input type=text> with focusout event handler
I have a <button> with click event handler
Focusout checks whether format in input box is correct. It does so by testing input value against a regular expression. If it fails it displays a message (a div fades-in and -out after some time) and refocuses my input by calling
window.setTimout(function() { $(this).focus(); }, 10);
since I can't refocus in focusout event handler. focusout event can't be cancelled either. Just FYI.
Click collects data from input elements and sends it using Ajax.
The problem
When user TABs their way through the form everything is fine. When a certain input box failes formatting check it gets refocused immediately after user presses TAB.
But when user doesn't use TAB but instead clicks on each individual input field everything works fine until they click the button. focusout fires and sets time-out for refocusing. Since time-out is so short focusing happens afterwards and then click event fires and issues an Ajax request.
Question
I have implemented my formatting check as an independent jQuery plugin that I want to keep that way. It uses .live() to attach focusout on all input fields with a particular attribute where format regular expression is defined.
Data submission is also generic and I don't want to make it dependant on formatting plugin. They should both stay independent.
How can I prevent click event from executing without making these two plugins dependant?
Example code I'm fiddling with
After some searching I've seen that all major browser support document.activeElement but I can't make it work in Chrome. FF and IE both report this being the active element, but Chrome always says it's BODY that is active even though click fired on the button element.
Check this code http://jsfiddle.net/Anp4b/1/ and click on the button. Test with Chrome and some other browser and see the difference.
You could use a flag...
Live demo: http://jsfiddle.net/Anp4b/4/
So your question is:
How can I prevent click event from executing without making these two plugins dependent?
Well, you obviously cannot prevent the click event. If the user wants to click the button, he will, and the click event will trigger. There's nothing you can do about that.
So the answer to the above question is: You cannot.
Based on the current conditions, you have to - inside the click handler - retrieve the validation result, and based on that result, decide if form submission should or should not occur.
JS Code:
$("#Name").focusout(function(){
var that = this;
valid = this.value.length ? true : false;
!valid && window.setTimeout(function() {
$(that).focus();
}, 0);
});
$("#Confirm").click(function(e) {
if ( !valid ) { return false; }
e.preventDefault();
alert('AJAX-TIME :)');
});
HTML Code:
<input type="text" id="Name">
<button id="Confirm">OK</button>
Is there are reason you use .focusout instead of .blur?
Using a flag is a good idea, but I would rather use a class on the element. By using classes to determine the state you can also style it accordingly. Here's my example based on your fiddle.
Another solution that hopefully gives the result you are looking for.
1) Create a named click handler:
var clickHandler = function(e){ /** submit form or whatever you want to do**/ };
$("button").click(clickHandler);
2) Add the following to the focusout event when it's failing validation:
$("button").unbind("click", clickHandler).one("click", function(){ button.click(clickHandler); return false;});
You can find an example of this here.

How do i find the new focus item with jquery?

I have a pop up dialog that lets you write text and does stuff when you click a button. My code is below
This function works, i find the new object by looking at e.originalEvent.explicitOriginalTarget. However now i notice if i press tab this function will be called but e.originalEvent.explicitOriginalTarget will give me the same current object instead of the new object. So my dialog doesnt close if a user presses tab to leave. How do i find the correct new dom item?
$('#Area').focusout(function (e) {
if ($(e.originalEvent.explicitOriginalTarget).closest('#Area').size() == 0)
$('#Area').hide();
});
event.relatedTarget worked for me. It will give the other DOM element, within the event, if there is one.
An example would be, if you had 2 buttons controlling the same function, and didn't want their code to be executed if they were clicked consecutively. You could attach a focusout event handler and check for an ID, or a class name.
$(".buttons").on("focusout", function (event) {
if($(event.relatedTarget).prop("class").indexOf("buttons") === -1) {
//code to execute
}
});
Perhaps a better example would be the issue I had.
I created a custom drop down list, that has a button beside it. The drop down list can be opened and closed by either clicking on the list, or the button. It can also be closed be losing focus to either object.
This becomes a problem in the following scenario.
1) user opens drop down list by clicking the list object.
2) user closes drop down list by clicking the button.
What happens is the list opens, but when the user goes to close the list, the list loses focus, which closes it, but since they are clicking on the button, it opens back up. The focusout causes the two objects to cancel each other out, in this type of scenario.
By writing the focusout event, I can now set it to only trigger when the relatedTarget doesn't have the same class as the target that called the event.
$(".listControl").on("focusout", function (event) {
if($(event.relatedTarget).prop("class").indexOf("listControl") === -1) {
//Close the drop down list
}
});
http://api.jquery.com/event.relatedTarget/
Check out this question/answer How to select an element that has focus on it with jQuery
I think the reason why you don't get anything with $("*:focus"); in Firebug console is when you click the console, the element loses focus.
And if you want to tackle it with events, the opposite of focus() is blur().
Edit
Maybe you can even try a different approach. If your only concern is watching for tab key, you can use .keypress() event and watch for tab keycode which is 9.

Categories