Looking for an explanation to the answers provided here and here.
Put simply, I have two elements. An input with an onBlur event, and a div with an onClick event. Without any special handling, when I blur the input by clicking the div, the onBlur event is fired, while the onClick event is not.
However, if I put a setTimeout inside the blur event handler, both event handlers are called when I click on the div. Why does this work?
HTML:
<input type="text" name="input" id="input1" />
<div id="div1">Focus the input above and then click me. (Will see 1 alert)</div>
<br/>
<input type="text" name="input" id="input2" />
<div id="div2">Focus the input above and then click me. (Will see 2 alerts)</div>
Javascript:
$(document).ready(function() {
function clickHandler() {
alert('Click!');
}
function blurHandler() {
alert('Blur!');
}
$('#input1').on('blur', function() {
blurHandler();
})
$('#input2').on('blur', function() {
window.setTimeout(blurHandler, 200);
})
$('#div1').on('click', function() {
clickHandler();
})
$('#div2').on('click', function() {
clickHandler();
})
});
Fiddle demo is here.
It happens because the blur event occurs before the click. The alert() method stops the execution of the script and once stopped, the click event will not fire after you dismiss the alert box. Using the setTimeout() method at the blur handler, you are actually allowing the click event to be fired.
i sugest you to listen to mousedown instead of click. The mousedown and blur events occur one after another when you press the mouse button, but click only occurs when you release it.
This is because of the modal nature of alert(). Try using console.log() instead and you will see that both will get called.
the setTimeout will fire the event after the time you defined.. so you'll have more time to click on the text.
in the other hand, the first input doesn't have a time to fire the blur so it's more difficult to fire the click event, but if you click fast enough, you will see two alerts even for the first input.
I am using a simplified example to describe the issue I am facing.
I have the following HTML markup:
<input ng-model="something" style="margin-top:8px;"/>
And, I have two HTML buttons:
<button id='submit'>Save</button>
<button id='btnGetAnalyzerInput'>Generate Analyzer File </button>
I used jQuery's change event on my input (to track whether any changes have been made to the input - by maintaining a simple JS variable).
When the user clicks "Generate Analyzer file button", what I want to is this:
Look up the JS variable to find out whether any changes have been made.
If yes, then prompt the user to save changes (window.dialog)
However, I find that when the focus is still on the input element, and when the button is clicked, the click event runs before the OnChange event. In all other cases, it is the OnChange event which gets fired before the click event (and so my code works as expected).
Is there any way to ensure that for such a scenario, the click event runs after the onChange event?
I am using Google Chrome to test my application.
Note :
Both events work as expected - the OnChange event gets fired when the textbox loses focus.
I can't use the keypress event since I want to track changes.
You could have the click event call the same function as the OnChange event. Something like this:
function OnChange(){
//Do stuff for on change;
}
function ClickEvent(){
OnChange();
//continue with generate stuff
}
You you may need to set up and pass in arguments to the OnChange function, depending on how you are accessing the data you need. If you need more guidance, post more of your code.
I have a textarea or input, and I change the text, and then click a link or button (without tabbing off the input), only the change event fires, not the click event. I want them both to fire:
Enter some text and then click the link. We want f1 and f2 to appear !
<br />
<input onchange="f1();" value="input text" />
<br />
click me
function f1() {
alert("f1");
return true;
}
function f2() {
alert("f2");
return true;
}
http://jsfiddle.net/paull3876/vrcfherp/3/
I've tried it with jquery and normal js as above, and I've tried setTimeouts inside the functions, I've tried input and textarea, but whatever I do, only f1 fires.
UPDATE 1
So we've established that alerts kill any subsequent events - good. Fiddle
Now the challenge is, how to stack up these events in an object so each event can fire an alert(or confirm, or ...) and NOT block any future events. I'm just trying different ideas. More to come...
UPDATE 2
I wrote some code to stack up the functions and then execute them at the end. Its not beautiful (and it should be wrapped in a class) but it works:
http://jsfiddle.net/paull3876/vrcfherp/9/
This behavior is due to the blocking mode of alert.
Browser will trigger the events one after the another. In this case the priority must be
onChange event of <input>
onClick event of <a>
but when it first executes onChange of input, it encouters alert which blocks rest of the things, hence the event onClick of anchor tag is not triggered.
Check this if you change from alert to console.log
alert() is modal and because input loses focus on other element mousedown, there is no click event fired.
So start using console for debugging purpose.
In the following example, I get only one alert box. I read that the focus is put before the JavaScript code is executed. Is there a way to get this to work on?
<input id="i" type="text" autofocus onfocus="alert(1)">
<script type="text/javascript">
document.getElementById('i').addEventListener('focus', function() {
alert(2);
}, false);
</script>
(I have only tested this in Safari)
Edit:
I can obviously do it this way (Prototypejs selector):
var autofocusElement = $$('input[autofocus]')[0];
callListener(autofocusElement);
But it looks ugly compared to only add an event listener.
Edit:
Do not worry over a lack of browser support for the autofocus attribute. It solved easily as I have done in I fiddle links to below. There is also the best solution to the problem as I can see. My question is if I can do it in a less ugly than having to call the listener manually.
http://jsfiddle.net/tellnes/7TMBJ/3/
It works fine in Firefox 3.6 since Firefox does not support autofocus. But in Safari, which supports autofocus, are not the event called.
From the HTML5 working draft:
There must not be more than one
element in the document with the
autofocus attribute specified.
So you're asking for undefined behavior anyway.
With only one autofocus element, under Firefox 3.6, neither of the handlers get called on page load. Manually giving the focus to the element calls both handlers (then proceeds into an infinite loop, due to the alert boxes giving the focus back to the element when closing).
The HTML5 draft does say that autofocus should perform the focusing steps on page load, including raising the focus event, but chances are that browsers are not currently implementing that feature in a complete or consistent manner.
You might want to explicitly call your focus event handler during page load until the HTML5 spec is finished and browsers start aiming for complete support.
The following code from your current example:
<input id="i" type="text" autofocus onfocus="alert(1)">
<script type="text/javascript">
document.getElementById('i').addEventListener('focus', function() {
alert(2);
}, false);
</script>
Is going to cause an infinite loop of alerts going from 1 to 2
[eidt]
because: (this happens only in broswers that support autofocus )
input gets autofocus, fires event which fires an alert, alert grabs focus, click ok, input grabs focus, focus event fires new event triggering now two different alerts (DOM fully loaded now so new event is added with another alert), both alerts grab focus, click ok, click ok, input grabs focus fires new event triggering now two different alerts, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events, input grabs focus, fires both events, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events, input grabs focus, fires both events, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events, input grabs focus, fires both events, alert grabs focus, click ok, next alert grabs focus, click ok, input grabs focus, fires both events...
Textual description of an infinite process FTW!....? :P
[/edit]
In your previous examples with two auto-focuses applied it seems that the last one will be executed as in the example I have attached at the bottom. I also added a way of adding a focus event to each input based on a class name... Not sure if you're looking for that but though it might be of some help.
JSFiddle Example of onfocus event
You need to give a value to autofocus.
<input id="i" type="text" onfocus="alert(1)" autofocus="">
Give autofoucs="autofocus" attribute after all events has been given to the input field.
You can also use addEventListener in .js file at the top.
It might be that the autofocus onfocus event fires before addEventListener adds the event listener.
I replaced autofocus with class="autofocus" on my input element, and set the focus like this near my addEventListener call:
if(searchInput.classList.contains('autofocus')) {
searchInput.focus();
}
If you need to execute a piece of javascript code, onfocus for either input, you could use jQuery: http://api.jquery.com/focus/
In a web page I have a button when clicked it calls a JavaScript function.
In that function I show a modal dialog box and I want to process keystrokes only at this time. That is when the modal dialog is visible.
When I close the modal dialog I want to stop the keystroke processing.
consider that I click a button and function sam() is called.
function sam()
{
document.onkeypress = function(e) { processKeystroke(e); }
}
So now a function is attached to the keypress event. Whenever a key is pressed the function processkeystroke will be called.
The function sam is called only after I display the modal dialog box.
Now I am closing the modal dialog and with that I don't want function(e) { processKes...} to be called.
What should I do to remove the attached event listener from document.onkeypress.
Also I would like to have alternatives for the above approach because that one I assumed of my own and I did not refer any specific documentation, so I am really going through trial and error procedure to use event handlers or listeners.
So when I call function sam I want a function to be attached with the keypress event and if I call another function form example closedialog() I want that keypress listening function to be removed. Because I want to write proper code which should not consume lots of system resources.
Just write the following code to remove the handler.
document.onkeypress = null;
Since you are talking about attaching you maybe should check jquery which provides real bind (attach) and unbind (detach) for events like keypress.