Hi and thanks for looking at my post. I'm very new to scripting, and I'm having a simple problem that I can't figure out. So...
I have a button that freezes up when I press it, and its "onclick" function doesn't get triggered. There is a "onmouseout" function that is causing this, but I don't know why.
I'd like "onmouseout" and "onclick" functions to apply to one button, but it's not working. Please see my code:
Javascript:
function popup()
{
alert("Hello World")
}
function pop2()
{
alert("Good job")
}
function pop3()
{
alert("CLICK ME!")
}
HTML:
<input type="button" onclick="popup()" value="Hello World">
<input type="button" onclick="pop2()" onmouseout="pop3()" value="click me">
Adjusting your code to isolate and provide detail to what's going on, I've prepared the following:
http://jsfiddle.net/238Nz/8/
Skip below this part for the answer. This is intended for Mark.
Let's ignore whether or not using on* attributes to add handlers is considered good or bad$. Also, let's use some logging to check the order. I am using console.log() to send messages to the browser's Javascript console. In Firefox, I use Firebug, and Chrome has a built-in console. In both, right-click on the page and Inspect Element, then choose the Console tab for these tests.
One more thing: jsFiddle can be a little complicated to figure out at first. The Javascript in the bottom, left pane is actually put within the head block above the input (and body tag) within the source. Right-click and View Source on the bottom, right (Result) pane and you'll see what the browser is using. It's just like your own example HTML document, just reordered for jsFiddle. Try not to be confused by how that works, though.
The markup I am using to test your problem is the following:
<input type="button" onclick="doclick()" onmouseout="domouseout()" value="Click">
Notice I plainly label my functions and use descriptive error messages. This helps me keep track of what is going on by embedding that detail within the code and the message log information. Always try to be descriptive in your labels (function, var, log information, etc.), instead of doing things like yay! or what happened. It's simply too hard to follow once your scripts get to be longer and more complex.
Next, I used the following function to narrow down and consistently replicate the same action:
function popup(msg) {
// Note, console.log is first here. This is so that the
// alert does not "steal" focus before I get any result.
console.log(msg);
// Now, let's try the alert. Notice, the same msg is used.
alert(msg);
}
This allows me to call both console.log and alert in a specific order, from both event handlers. Next, I establish my two event handler functions:
function doclick() {
popup('onclick fired');
}
function domouseout() {
popup('onmouseout fired');
}
See, all they do is call popup() with an action-specific log message about what was supposed to happen. Since alerts are designed to "focus" to the user and block interaction, which appears to be a possible cause of the "frozen" browser frame.
What I do next is try this in different browsers. Always try to replicate and test across different browsers#. In this case, I notice a big difference between two...
Chrome: Does not block processing; both alerts fire, and the onmouseout-fired alert is not run through console.log until after I hit Ok on the alert and and I move the mouse pointer off of the input element. This, it seems, is the desired outcome. Right?
Firefox (17.0.1): Firefox does show the behavior you're describing. Note, when I click on the button, I get both doclick and domouseout() called at the same time. So Firefox is detecting the onclick as taking the mouse pointer away from the button, and you get the "freeze". If you watch the console, you'll see both logs fire immediately, and you seemingly get no alert to interact with (by clicking Ok).
IE (7-9, 9 Compatibility View): IE of course provides an interesting illustration. For instance, when I click the button in IE9, I see:
http://i.imgur.com/sWXWm.png
Which of course appears to be the same effect Firefox is having... But for some reason with Firefox, the onmouseout-fired alert does not focus on top of the onclick-fired alert. IE 7-9 plus Compatibility View all exhibit this particular behavior, with slight variations.
Opera (12.02): Opera does not fire the onmouseout-fired alert or console.log message until after the onclick-fired alert and log message, and you move the mouse (assuming you've moved it off of the input button element after clicking it). This seems weird, but more palatable than the Firefox and IE behaviors. Maybe I'm mistaken, though.
So what's happening? I'm not quite sure, but I think that the onmouseout is blocking the onclick's alert from focusing to the user. If you hit [Enter] while it's frozen, you get the onclick alert but no onmouseout. Chrome seems correct here; Firefox's "popunder" alert seems, well, sorta fishy.
In summary, at least the behavior of the two events in this case are not only specific to Firefox. What seems to be specific to Firefox (at least 17.0.1) is the fact the onmouseout-fired alert does not focus correctly, and the page "appears to freeze". This seems like a bug. I wonder if it's been reported?
$
It's not usually a good idea to use inline attribute event handlers like <input onclick="doclick()"...>, but let's ignore what's beside the point here. See MDN's DOM Event documentation, specifically the HTML attribute section, and realize this is a bit trickier and detailed than is worth going into here.
#
If you continue working with Javascript within the browser, you'll find out IE is... special. It has a special place in history, so weird or "abnormal" behavior is not unusual when checking your code with versions of IE. Personally, I suggest learning and working within Firefox or Chrome, and then checking in IE and other browsers that it works.
Javascript:
var clicked = false;
function popup()
{
alert("Hello World")
}
function pop2(ev)
{
alert("Good job");
clicked=true;
}
function pop3()
{
if(clicked == false)
{
alert("CLICK ME!");
}
clicked=false;
}
HTML:
<input type="button" onclick="popup()" value="Hello World">
<input type="button" onclick="return pop2(event)" onmouseout="pop3()" value="click me">
link to demo
Since the click and mouseout/mouseleave events occur soon after the other on FireFox due to poor focusing during click event, we can add a sort of a delay for the code that will be processed during mouseout/mouseleave event. The following worked for me:
//Bind the element with classname to a function on click event
$(".rej").bind("click", showData);
//Bind the same element with classname to another function on mouseout event.
$(".rej").bind("mouseout", hideData);
Then you can proceed with your showData function. However in hideData function you will need to add a delay of few seconds before processing the code in that function, as show below:
function showData() {
//Do something
}
function hideData() {
var delay = 1000;
setTimeout(function(){
//Do something
}, delay);
}
And you're good to go. The mouseout event no longer overpowers the click event in Firefox. :) :)
Related
I am experiencing the following issue: After a particular jQuery library loads, if you click on a number input arrow, the input value keeps increasing (or decreasing) until the focus is shifted outside the input element.
Binding an input event to the element showed it keeps triggering, which led me to believe some piece of code kept setting element.value in a loop. But that did not happen.
I've tracked the issue down to calling event.preventDefault() on a mouseup event.
See:
document.body.addEventListener('mouseup', (e) => {
e.preventDefault();
});
<input type="number">
Why does this happen?
I had trouble finding information by searching what causes these infinitely increasing inputs.
Only after finding the cause myself, I've found out about a similar bug that happened with preventing the default of mousemove (https://stackoverflow.com/a/37521764/6849064). Although, this one does not seem to happen anymore.
Looks like this is a Chrome (and Edge) bug. But as https://stackoverflow.com/a/65253876/6849064 said, it is actually default behavior which makes sense in the way he said it. I myself failed to find this standard behavior documented anywhere. One way to fix the problem is to stop bubbling of the event up to the document,
document.querySelector('input').addEventListener('mouseup', (e) => {
e.stopPropagation();
});
And the other is, well, not preventing default behavior.
The following issue has nothing to do with jQuery. The issue is the code is doing exactly what you wanted it to do.
In the code <input type="number" /> has got 2 events. One is 'mousedown' and second is 'mouseup'.
Consider following example: https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_event_preventdefault2
The same is represented in the example above.
What you are doing is cancelling the 2nd part, ie mouseup so if you do mousedown and cancel mouseup, then the number will:
Go on increasing if you push uparrow
Go on decreaseing if you push downarrow
The only, surprise is this would have perfect sense if you would have written the code adding event to input rather than body, but anyways seems browser by default is increasing or decreasing number -- based on event-bubbling to body.
Note: The issue is replicated below, while no jQuery has been added!
document.body.addEventListener('mouseup', (e) => {
e.preventDefault();
});
<input type="number">
I have jEditable working fine with a textarea to edit the content inside an object. I'm submitting onBlur using jEditable's onblur option directly to a function (instead of an url) and all works as expected UNLESS you change windows using for e.g. alt+tab. When I use alt+tab it looks like the content is submitted through an actual http request ignoring my callback function.
My very basic sample implementation looks like this:
$(".editable").editable(function(content,settings){
content = content.replace(/\n/gi,"<br />");
return content;
},{
data: function(value, settings) {
return value.replace(/<br[\s\/]?>/gi, '\n');
},
type: "textarea",
onblur: "submit"
});
You can test it here: http://jsfiddle.net/xmajox/wePp5/
I've tried all other window operations: resize, move, etc and even moving between tabs on the browser works great (submits the data and exits the edit mode).
Any ideas of how this might be tamed?
UPDATE:
After a few more tests and some colaboration from other people, it seems that this depends on the os (window manager?). It happens consistently on ubuntu 12.10 with unity but doesn't happen on mac or windows (haven't tested other linux boxes).
Also, it is now proved that my callback method does run when I use alt-tab but the form gets POST'd anyway afterwards. Adding a live preventDefault didn't seem to help.
Found the fix for this, but coulnd't quite understand why it happens on such a specific situation.
First of, I must be the (un)luckiest guy in the world because I've tried this on 10ths of other combinations and it didn't have this problem, only place I could get it to happen was:
Ubuntu 12.10 (with Unity) and Chrome (v22 at the time of this post)
Disclaimer: This doesn't mean it does not happen on other places, I just couldn't reproduce it on the ones I tested (or asked friends to test).
Problem:
When focus is lost, jEditable - as of version 1.7.1 - sets a timeout before actually executing any action (200ms by default) to prevent duplicate actions according to the comments in the source. If you (using the above browser/os combination) alt+tab out of the browser window before the timeout is fired (aka. before the data is submitted and your method is ran) it will force a POST request with the data, completely ignoring the preventDefaults or return falses. It won't have this problem if you press alt... keep it pressed (more than those 200ms, i.e. enough time for the timeout to be fired) and then press alt to move away.
Solution:
I edited jEditable's source to reduce the timeout (or even remove it). So I around line 280, where it says:
(...)
input.blur(function(e) {
// prevent double submit if submit was clicked
t = setTimeout(function() {
form.submit();
}, 200);
});
(...)
I changed it to:
(...)
input.blur(function(e) {
form.submit();
});
(...)
Notes:
I removed this because on my situation (submitting textareas ONLY on blur and without any other controls that allow the user to submit the data) I coulnd't reproduce the double submit issue that Mika Tuupola was mentioning on the comments. If you have text input fields (that are submitted pressing enter) with the submit onBlur active, you might fall into that situation. On those cases I suggest you just reduce the timeout or simply avoid to use onBlur submits.
Safari helpfully (?) prompts before closing a tab or window when text has been entered into an input.
There are some cases where, as a web developer, this isn’t desirable — for example, when the input is a live search where the user has probably already gotten the results he’s looking for when the window is closed, even though there’s still text in the field.
How can I let Safari know that text in a particular input doesn’t need its protection?
It seems like you are able to disable this warning for an entire page by having an onbeforeunload handler on <body> (even an empty one will do). For example, the following will not produce the warning:
<body onbeforeunload="">
<form method="get"><input></form>
</body>
I'm not sure if this is the intended behaviour, or a bug.
I think I've got a solution to this problem, though it's unquestionably a hack (i.e. if Safari changes how this feature is implemented, it could stop working). Shown here with a touch of jQuery:
$('.unimportant').live('blur', function(){
var olddisplay = this.style.display;
this.style.display = 'none';
this.clientLeft; // layout
this.style.display = olddisplay;
});
Demo (try typing in the "unimportant" field, click somewhere else on the page, then close the window).
In short:
Hide the input
Trigger layout
Show the input
You can also change the value of the input, trigger layout, and change it back.
The one limitation here is that cleaning the input has to be done explicitly. In this case, it will be dirty until blur. This works well in my situation, and probably in many others, since the input will be protected from an accidental window close until something else on the page is manipulated (e.g. a link is clicked). You could choose to run this on keyup if you're willing to live with a flicker of the insertion point every time a key is pressed.
I'm open to cleaner solutions.
I found what I think is a pretty good solution to this problem. When I use AJAX to submit the form then I want the warning to suppress. This is accomplished with onbeforeunload.
window.onbeforeunload=function(e){}
But after I submit I might make additional changes and so I want the warning to show again. To do this I added a keyup handler to a form element.
$('txtarea').onkeyup=dirty;
What dirty does is checks is the input field has changed if it has then I set onbeforeunload to null.
function dirty(e){
if (e.srcElement.value != e.srcElement.defaultValue){
window.onbeforeunload=null;
}
}
I just found another solution to prevent Safari from displaying the "Are you sure you want to reload this page?" dialog when textareas have changed their content.
It turns out that setting the value through Javascript clears Safari's changed state:
$(document).on('blur', 'textarea', function() {
var value = $(this).val();
$(this).val('').val(value);
});
Clearing the value first is important, directly setting it to the content it already is does not work.
EDIT Apparently setting window.onbeforeunload to an empty function still works, however $(window).on('beforeunload', function() {}) does not.
I'm having problems with .live() and confirm. It's multiplying the confirm dialogs for every click. I know about .die() but i can't get it to work.
$("button.del").live("click", function(){
if(!confirm("Are you sure?")) {
//close
}
});
I've tried $("button.del").die("click"); right after the above code, in which case the confim doesn't even fire.
Does the dialog box appear multiple times if you just run that code by itself?
If the dialog box is appearing multiple times, one likely explanation is that you are accidentally running this .live() binding more than once. If that happened, you would see one dialog box for each time you bound an event to the button.
Make sure you are only attaching this function to the button once.
If you take a look at this standalone example, you can see that your code is fine.
Can you post the HTML as well.
One cause I can speculate for this is that the .del class is specified into some child class, and the event is firing on both parent and child. This would happen for the following:
<div class="testclass">
test
<div class="testclass">
test2
</div>
</div>
...
$(".testclass").click(function() { alert("test"); });
Another reason would be if you accidentally bound it twice, i.e. the following would cause the same problem
$(".testclass").click(function() { alert("test"); });
$(".testclass").click(function() { alert("test"); });
We really need to see more of your code. You must utilise live for a reason. Do you get the same result with a simple click() binding?
Thank you all for your replies...turn out it was a bug in my code... Sorry...
I didn't see it... the part of the code with confirm was reloading on every click...hence the multiplying...
I have a page which does quite a bit of work and I don't want the user to be able to navigate away from that page (close browser, hit back button, etc.) without getting a warning. I found that the onbeforeunload event (which I think is IE-specific, which works fine for me as the project uses lots of ActiveX) works great.
Problem is, I want the user to be able to click on a little "help" icon in the upper-right corner and pop up a help window at any time. This causes onbeforeunload to fire, even though the main window never goes anywhere and the page never unloads.
The JavaScript function that runs when the onbeforeunload event runs just puts text into event.returnValue. If I could ascertain, somehow, that the help icon is the one that was clicked then I could just not put text into event.returnValue in that situation. But how could I have the page figure that out?
Let me guess: the help "icon" is actually a link with a javascript: url? Change it to a real button, a real link, or at least put the functionality in an onclick event handler (that prevents the default behavior). Problem solved.
<!-- clicking this link will do nothing. No onbeforeunload handler triggered.
Nothing.
And you could put something in before the return false bit...
...and the onunload handler would still not get called... -->
blah1
<!-- this should also do nothing, but IE will trigger the onbeforeunload
handler -->
blah2
EDIT: My "workaround" below is complete overkill, based on my lack of understanding. Go with Shog9's answer above.
OK so while I was writing the question, I came up with a workaround which will work for now.
I put a global JavaScript variable in act as a boolean on whether or not the icon is being hovered over. Then, I attach events to the image's onmouseover and onmouseout events and write functions that will set this value. Finally, I just code in the function that handles onbeforeunload that will check this value before setting event.returnValue.
Probably not a flawless workaround but it will work for now.
on the internet you will find many people suggesting you use something like
window.onbeforeunload = null
but this does not work for me in IE6. reading up in the MSDN docs for the event object i found a reference to the event.cancelBubble property, which i thought was the solution. but thanks to Orso who pointed out that setting "event.cancelBubble=true" is useless, the way to get rid of the confirm prompt is to exclude the return statement altogether, i chose to use a boolean variable as a flag to decide whether to return something or not. in the example below i add the javascript code programattically in the code behind:
Page.ClientScript.RegisterStartupScript(typeof(String), "ConfirmClose", #" <script> window.onbeforeunload = confirmExit; function confirmExit() { if(postback == false) return ""Please don't leave this page without clicking the 'Save Changes' or 'Discard Changes' buttons.""; } </script>");
then the help button contains the following aspx markup:
OnClientClick="postback=true;return true;
this sets the 'postback' variable to true, which gets picked up in the confirmExit() function, having the effect of cancelling the event.
hope you find this useful. it is tested and works in IE6 and FF 1.5.0.2.
I have a method that is a bit clunky but it will work in most instances.
Create a "Holding" popup page containing a FRAMESET with one, 100% single FRAME and place the normal onUnload and onbeforeUnload event handlers in the HEAD.
<html>
<head>
<script language="Javascript" type="text/javascript">
window.onbeforeunload = exitCheck;
window.onunload = onCloseDoSomething;
function onCloseDoSomething()
{
alert("This is executed at unload");
}
function exitCheck(evt)
{
return "Any string here."}
</script>
</head>
<frameset rows="100%">
<FRAME name="main" src="http://www.yourDomain.com/yourActualPage.aspx">
</frameset>
<body>
</body>
</html>
Using this method you are free to use the actual page you want to see, post back and click hyperlinks without the outer frame onUnload or onbeforeUnload event being fired.
If the outer frame is refreshed or actually closed the events will fire.
Like i said, not full-proof but will get round the firing of the event on every click or postback.