Recently i got stuck on an issue when using DOM event handlers. Next i´ll describe the problem related stuff:
The code
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<form >
<input id="b1" type="submit" value="Click" />
</form>
<script>
//global variable
var v= 0;
var b1= document.getElementById("b1");
b1.addEventListener("click", f1, false);
function f1() {
window.alert(++v);
}
</script>
</body>
</html>
How the code should work?
When the button(b1) is pressed, the global variable(v) increases its value progressively for each new click of the button.The window will alert the new value.
The problem:
The variable doesnt keep its latest value.For example, when i click the button twice, the window should alert 2 but instead im still getting 1.
Assertions:
The global variable(v) should keep the changes done to it inside a function.This is due the fact that im using it directly on the function,without using an argument.
Notes:
When i invoke the function twice directly on the code it works correctly(instead of the handler).
f1();//1
f1();//2
I´ve tested it with Chrome and Firefox.
So, what´s happening here? why doesn´t it works correctly? does the event handler works differently with the global variables?
Hope you guys can help me! Thanks!
You need to add a form onsubmit handler that cancels the submit. The value is being reset because the page reloaded.
<form onsubmit="return false;">
<input id="b1" type="submit" value="Click" />
</form>
That would do it.
Here's a jsfiddle. Try removing and adding the onsubmit handler to see it more clearly on the jsfiddle.
You could optionally also switch the click event out for an onsubmit on the form and use preventDefault on your onsubmit event instead of using the onsubmit in the HTML, at least in modern browsers. In older versions of IE you had to do it a little differently.
function f1(event) {
event.preventDefault();
window.alert(++v);
}
This issue is that the submit button is submitting your form, most likely causing the page to refresh and reset v to 0. You can prevent this behaviour with the preventDefault method on the event object that gets passed to your callback function:
//global variable
var v= 0;
var b1 = document.getElementById("b1");
b1.addEventListener("click", f1, false);
// e is the event object
function f1(e) {
// calling preventDefault will prevent the form from being submitted
e.preventDefault();
console.log("b1 click", ++v)
}
Just a stylistic note, it's confusing to use ++v. You're better off using v += 1;
As already established, you are seeing this behavior because clicking the button submits the form and reloads the page.
The simplest solution is to remove the <form> element.
Related
This question is inspired by this post.
In a nutshell: Why window.location.href is not redirecting to a new page (example.com) when executing the code below?
<form>
<input type="submit" id="submit" value="Submit">
</form>
<script>
document.getElementById('submit').addEventListener('click', function (e) {
window.location.href = "http://www.example.com";
});
</script>
I've always believed, that setting window.location.href immediately loads a new page, but in this case it doesn't. Submitting the form just reloads the page instead, and setting a new location seems to be totally ignored. Why? How? What I'm missing here?
Please notice, that I'm aware of several ways how to prevent form submitting in this case, rather I'd like to know, why setting location.href is ignored, what is the mechanism behind the behavior? I've tried to search explanation from the standard, but haven't found anything so far.
Additional information
This seems to happen in all major browsers (Chrome, Firefox, IE11, Edge ...), but not when the code is run in a Stack snippet (because it's sandboxed, and won't send forms anyway). A console.log put in the function shows, that the click handler is executed before the actual submission is executed.
A jsFiddle reproducing the issue.
You can see easier here what is happening step by step if you will try tu change location drunning form submission
JSFIDDLE
If you will check your browser network tab than you can see that the submit request is cancelled (but still sent) by redirect request. I believe that same situation occurs when you trying to do it onclick or onsubmit the first request just cancelling the next one and prevent window.location.href redirection.
I belive the key thing here is not to view the problem as 'form submission vs page redirect', but as an event-listeners issue.
What you are doing is to attach an event listener to an html element. And it seems that the policy of DOM elements is to execute all the event listeners first, and then the event itself . In your case, the page is redirected to the url you provided, because you set window.location inside the listener, then the submit event itself takes place, so the same blank page is reloaded
The fact that "event flow process will complete after all listeners have been triggered" is stated here: http://www.w3.org/TR/DOM-Level-2-Events/events.html
So far I haven't figgured out a way to execute the listeners after the event , but if that can be done, that is all you need to make this example work
The main issue is that there is nothing preventing the submit button from actually submitting the form. You would need a return false somewhere for that to happen. I'm not fully certain whether the Submit button logic or the click handler is happening first, but regardless, the form post is taking precedence.
I was able to get the following to work:
<html>
<head>
<script type="text/javascript">
function redirect() {
window.location.href = "http://www.example.com";
return false;
}
</script>
</head>
<body>
<form method="GET" action="">
<input type="submit" id="submitbtn" value="Submit" onclick="return redirect()" />
</form>
</body>
</html>
This example does remove the programmatic addition of the click event, but if that's a hard requirement it should be possible to add that back in.
I don't know what is wrong with that, because I was following at every step the tutorial from jquery.com regarding the form submit event.
My Javascript:
[Ofc. latest jQuery library is included].
<script type="text/javascript">
$("form#addFav").submit(function(event) { event.preventDefault(); alert("hello"); });
</script>
Have also tried with the $(document).ready() event:
$(document).ready(function(){
$("form#addFav").submit(function(event) { event.preventDefault(); alert("hello"); });
});
Here is my HTML form code:
<form action="" id="addFav">
<input type="text" name="name" class="thin-d"/>
<input type="submit" value="Send"/>
</form>
So, regarding the above Javascript code, it is supposed to work (I mean it should prevent default action [submitting form] and send the alert then), but it all doesn't work - have tried with thousands of combinations, but I fail'd. So I'm waiting for your solutions. I'd appreciate every one.
You probably have some syntax error or somthing like that somewhere else, because what you have just works.
Are you sure there aren't any JS errors?
P.S. I would alwyas go for the latter code to ensure that the elements are in the DOM before trying to attach events.
For anyone else who has the same problem, and still struggling to solve this issue, try to see if you have illegally reused the id, and try changing the form id to something unique.
I had accidentally given the id to two different DOM elements and the event was being bound to the first element with the respective id and my form was the second one so it was never captured. This had me pulling my hairs for quiet a long.
I just recently ran into the same issue. Jquery on submit would not work on the form, however just changing it to click event worked fine. Still at a loss why .on(submit) or .submit() events will not recognize the form.
$("form#addFav").click(function (event) {
event.preventDefault(); alert("hello");
$(this).submit();
});
this question is old but.. you might have had another submit events firing before yours fired. If these other events contained "return false;" statement then the event execution got interrupted and your code never fired. To put your code BEFORE these events you might use ONSUBMIT form attribute where you can put code that will fire before or at the same time as other events.
When you have more than one submit button in a form, is there a way to know which one fired the onsubmit event without adding code to the buttons themselves?
Edit: I need to do the check on the client-side, i.e. with JavaScript.
The "submit" event is not fired by the button, but its fired by the "form". A quick test proves this:
<form id="myform">
<input id="email" type="text" value="1st Email" />
<input id="action1" type="submit" value="Action 1" />
<input id="action2" type="submit" value="Action 2" />
</form>
<script type="text/javascript">
document.getElementById("myform").onsubmit = function(evt) {
var event = evt || window.event;
alert(event.target.id); // myform
alert(event.explicitOriginalTarget.id); // action2 (if action2 was clicked)
// but only works in firefox!
}
</script>
Although in firefox, you can use event.explicitOriginalTarget property on event to get the input (submit) that was clicked causing the submit event to be fired. (if you want to know)
So best options for you are:
Have a different value to your submit buttons OR
Have those as normal buttons and click handlers to them via javascript.
There is a submitter attribute on SubmitEvent object.
See example:
<!DOCTYPE html>
<html>
<body>
<form action="./test.html" onsubmit="myFunction(event)">
Enter name: <input type="text" name="fname">
<button id="firstButton" type="submit">Button 1</button>
<button id="secondButton" type="submit">Button 2</button>
</form>
<script>
function myFunction(event) {
// This should log id of the button that was used for submition
console.log(event.submitter.id);
// Prevent sending the form (just for testing)
event.preventDefault();
}
</script>
</body>
</html>
See https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter
Does having an event listener on each button count as adding code? Otherwise, there's no way to see what button triggered the submit event, unless you want to get down and dirty and calculate the mouse position during the event and compare it to button positions.
Otherwise, the next best thing would be to assign an event handler for the click event of button and assign the name of that button to a variable you can check in the form's submit event.
There are a couple of ways that I can think of.
You can use different values, and your unobtrusive javascript can help with it.
One discussion on this approach (using different values for each button) is here:
http://www.chami.com/tips/internet/042599I.html
I tend to go with using different name attributes for each button.
A blog on that is here: http://www.codetoad.com/javascript/multiple.asp
I don't follow either of these, which approach will work best is going to depend on different factors, such as, are you handling the submit buttons in javascript, or will the server get the form, then have to figure out what the user wanted.
Personally, I prefer to use the ajax approach, now, where I just attach events to the buttons after the page is loaded, using unobtrusive javascript, and then based on the user choice call out to the correct function, but that depends on whether you can add a script link to the html page.
UPDATE:
In order to do this with javascript, the simplest way is to attach an event on the click of the button, and then look at the name to decide how to handle it.
In actuality, the form never truly has to be submitted to the server, but you can handle everything in the background by wrapping up the parameters (options) and sending them to the server, and let the user know the results.
Sorry to warm up this very old thread. The question hadn't been answered here but only approaches for practical workarounds have been given here before.
But the event-object does carry information about which object has initiated it. In a handler b4submit(e) you can get the submit-button like this:
function b4submit(e) {
var but = e.originalEvent.explicitOriginalTarget;
...
}
And but is an HTML Object with all the attributes you've assigned it with, like name, id, value etc.
I came across this after some debugging, and I thought it might be of a wider interest as a clean solution for this issue.
For me the simplest option that worked for me is to use document.activeElement if you want to get the id use document.activeElement.id if you want to get the text content you can simply put document.activeElement.textContent
const onSubmit = () => {
console.log('document.activeElement', document.activeElement.id)
if (document.activeElement.textContent === 'Suivant') {
handleNext()
return
}
if (document.activeElement.textContent === 'Confirmer') {
console.log('Payer')
return
}
}
Correct me if I am wrong, but seems to me jQuery event handling is completely separate from the javascript event handling. I know that the order of executing jQuery and javascript event handlers themselves is undefined, but can the assumption be made that all javascript handlers will execute before jQuery ones?
In the example given in an answer to this question that seems to be the case.
Also, is there any preference on executing inline javascript event handlers in respect to bound ones?
For clarification, I am asking all of this because I encountered a problem where I have an inline event handler on onClick event of an <a> element that calls the submit() method of an enclosing form. Just before submitting the form, I want to dynamically add some hidden inputs to the form. Right now I am doing this:
var preSubmit = function preSubmit()
{
// add inputs
}
var oldSubmit = form.submit;
form.submit = function newSubmit()
{
preSubmit();
oldSubmit.call(form, arguments);
}
But I'm really wondering if there is a more elegant way and I really need some clarification on this.
I'm not sure about the specs but I presume that event handlers are just queued in the same order as you define them. Inline handlers are defined right in the DOM node so nothing else can go earlier.
The most elegant way is to write all your JavaScript in an unobtrusive way, i.e., keep it separated from HTML (you appear to be mixing programming styles). Whatever, you can intercept form submission by attaching an onsubmit handler to the form:
$("form").submit(function(){
// Do stuff
return true;
});
Update
I've done some testing and it appears that an onsubmit handler attached to a form via jQuery does not get triggered when you call the DOM's submit() method somewhere else. Here's a workaround:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript"><!--
jQuery(function($){
$("a").each(function(i, a){
a.onclick = function(){ // Remove previous handlers
alert("I will no longer submit the form");
$(this).closest("form").submit();
};
});
$("form").submit(function(){
alert("I'll take care myself, thank you");
$("input[name=foo]").val("Another value");
return true;
});
});
//--></script>
</head>
<body>
<form action="" method="get">
<input type="text" name="foo" value="Default value">
Submit form
</form>
</body>
</html>
There are two solutions: Wrap the submit function of the form or the onClick handler of the link. I'm not aware that jQuery offers a "wrap existing function" API.
As for the run order, jQuery is JavaScript, so the handlers run when the browser runs them. That's not something specific to jQuery, except when the API states that something is run asynchronously.
Asides from the detail of your question, you could just add an onsubmit event, which will be called before the form submits anyway...
Consider an HTML form:
<form action="" method="POST" onsubmit="return checkValidArray()">
<input type="text" name="data" onchange="return validate(this);">
</form>
It appears (in both IE 6 and Firefox 3) that when you type some text into the input field and click submit that the onchange event fires for the input field, but the onsubmit event does not fire for the form until you click the submit button a second time (at which time the onchange does not fire, of course). In other words, the onchange seems to prevent the onsubmit from firing.
The desire is to check each field in the form when the user exits the field in order to provide them with immediate validation feedback, and also to prevent submission of the form if there is invalid data.
[EDIT: Note that both validation functions contain an alert().]
How does one get around this problem?
Solution (of a sort):
It turns out that it is only presence of an alert() - or a confirm() - during the input's onchange event that causes the form's onsubmit event to not fire. The JS thread appears to get blocked by the alert().
The workaround is to not include any alert() or confirm() in the input's onchange call.
Browsers known to be affected:
IE6 - Windows
IE8 - Win
FF3 - Win
Browsers known not to be affected:
Google Chrome - Win
Safari - Mac
FF - Mac
I tried with Firefox 3 (Mac) with the following code:
<html>
<head>
<script>
function validate(ele)
{
alert("vali");
return false;
}
function checkValidArray()
{
alert("checkValidArray");
}
</script>
</head>
<body>
<form action="" method="POST" onsubmit="return checkValidArray()">
<input type="text" name="data" onchange="return validate(this);">
<input type="submit" value="Ok">
</form>
</body>
</html>
It seems to work. When I click on the Ok button, both "Vali" and "Check Valid Array" pop up.
Initially I thought return false could be the reason why the form was not submitted, but it IS submitted (at least, checkValidArray() is called).
Now, what are you doing in your checkValidArray() and validate() methods? Something special? Can you post the code?
EDIT: I tested with IE8 and FF3 on windows, and here both events do not get fired. I have no idea why. Perhaps onblur IS a solution, but WHY does onchange not work? Is there a specific reason or is it just another inconsistency? (Works on both FF and Safari on Mac)
You could use the onblur event in your inputs instead of onchange.
It's quite interesting that the behaviour is different on the Mac, so it appears platform dependent and not browser dependent. Must be a clue there somewhere...
I tried onblur with Nivas' code but had the same result as with onchange (only the "Vali" alert).
What does make a difference is whether you do anything in validate(). Comment out the line alert("vali"); and it works! (The actual return value from validate() does not matter, although I wouldn't expect it to.)
EDIT:
A colleague just tried this in Google Chrome on Windows and it works there. This intuitively makes sense because of how Chrome separates JS threads.
Something about the first alert() blocking the thread causes the onsubmit event to get lost. Possible race condition?
Don't create ; submit button. Instead, create a normal button and write a function which can be called onClick with that button.
Function will do the validation on the form fields, and if everything is fine, it will submit the form. Otherwise it will not.
function validate
{
"Piece of code to Validate your form"
document.formName.action.value = "URL which you want to call"
document.propFile.submit(); // It will submit he page
}