I've been binding submit events to forms, and ensuring that they do not break the form, using jQuery like this:
jQuery('form').submit(function(e){
var form = this;
e.preventDefault();
alert('1');
setTimeout(function() {
alert('2');
form.submit();
}, 1000);
});
This is all good and well, except, if for some reason a front end developer gave a child input of this form an id of ="submit", this breaks, as form.submit()
throws a JavaScript error (In Chrome, 'Uncaught TypeError: Property 'submit' of object # is not a function').
You can see an example of that happening here: / (Here's the behavior if there's no <input id="submit">
: /
Now, I know I can prevent this from binding on forms that have children with an id of 'submit' with jQuery('form').not(:has('#submit')).submit()
, and the form will process just fine, but my binding will never fire for those forms.
So, the question: How can I safely bind this jQuery function to all forms, including those with <input id="submit">
?
EDIT: Worth noting that this problem doesn't go away if I unbind the submit handler and then trigger a jQuery submit on jQuery(form)
.
I've been binding submit events to forms, and ensuring that they do not break the form, using jQuery like this:
jQuery('form').submit(function(e){
var form = this;
e.preventDefault();
alert('1');
setTimeout(function() {
alert('2');
form.submit();
}, 1000);
});
This is all good and well, except, if for some reason a front end developer gave a child input of this form an id of ="submit", this breaks, as form.submit()
throws a JavaScript error (In Chrome, 'Uncaught TypeError: Property 'submit' of object # is not a function').
You can see an example of that happening here: http://jsfiddle/q68ky/ (Here's the behavior if there's no <input id="submit">
: http://jsfiddle/JpXzL/
Now, I know I can prevent this from binding on forms that have children with an id of 'submit' with jQuery('form').not(:has('#submit')).submit()
, and the form will process just fine, but my binding will never fire for those forms.
So, the question: How can I safely bind this jQuery function to all forms, including those with <input id="submit">
?
EDIT: Worth noting that this problem doesn't go away if I unbind the submit handler and then trigger a jQuery submit on jQuery(form)
.
-
I know an ideal world, I should never create
id="submit"
on an input form, but I can't guarantee that it won't exist. – Yahel Commented Dec 16, 2010 at 20:25 - 1 @ys, you do understand that this code will result in an endless loop right ? – Gabriele Petrioli Commented Dec 16, 2010 at 20:47
-
@Gaby no,
form.submit()
is triggering submit on the DOM element, not the jQuery element. if it was$(form).submit();
you'd be right, and I'd need to unbind the jQuery handler, like here: jsfiddle/LKUhV. Also, as you see on the original jsfiddle, it doesn't result in an infinite loop ofalert()
being triggered. – Yahel Commented Dec 16, 2010 at 20:49
5 Answers
Reset to default 4The only way I can think of:
(function () {
var method;
window.submit = function (theForm) {
if (!method) {
method = document.createElement("form").submit;
}
method.call(theForm);
};
}());
Then call submit(theFormYouWantToSubmit)
.
You can see it in action here: http://jsfiddle/q68ky/2/
Edit: To provide some explanation as to what this does....
This method creates a new form element (document.createElement("form")
), and stores a reference to the "submit" attribute of it (method = document.createElement("form").submit
). Because this is a newly created form element, with no child nodes, we can guarantee that the "submit" attribute is actually the "submit" method we need, rather than a child node with an id/name of "submit".
We then use the call
method (part of Function.prototype
), which sets the context of the submit
method to the form we want to submit, rather than the window
object, which is what it would otherwise be on.
The rest of the gubbins in the snippet caches the submit
method, so that all of this (albeit small) overhead does not take place every time you want to submit the form, and captures the cached method in a local scope, instead of holding it in the global scope and polluting the global namespace.
As this is actually a non-jQuery problem, here is a non-jQuery solution:
HTMLFormElement.prototype.submit.call(form);
DEMO
Reference: HTMLFormElement
Update: Access to the DOM prototypes is only possible in IE8+. (and that is probably the reason why jQuery does not use it).
@Matt's answer instead should work in any browser
In addition the problem I identified in my other answer, there is an open jQuery bug exacerbating the issue:
.SUBMIT() CAN FAIL IF SOMETHING HAS ID="SUBMIT"
If an element with an ID of submit exists in a form, .submit() can fail. It's important that this function (in particular) work correctly.
http://bugs.jquery./ticket/1414
Instead of form.submit();
, you need
$(form).submit();
This is because form
is just the bare DOM element, while $(form)
is the jQuery object. Calling form.submit()
is trying to access the submit
property of form
. Since it doesn't have one, it's defaulting to the old-school behavior of getting the child element whose id
is submit
(hence the "is not a function" error).
The error occurs if a form element's name or id is 'submit'. It looks like it's an issue with jQuery.