Spot the error - it may not be what you think

This post is more than 2 years old.

I just helped a coworker diagnose this issue and it can be incredibly subtle if you aren't paying attention. Consider the following simple form:

<html>

<head> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script> $(document).ready(function() { $("#myButton").click(function() { $.post("test.cfc?method=whatever&returnformat=json", {}, function(res) { console.log('back from cfc'); },"json"); }); });

</script> </head>

<body>

&lt;form method="post"&gt;	
&lt;input type="button" id="myButton" value="Click me like you mean it."&gt;
&lt;/form&gt;

</body> </html>

I've got a button that - when clicked - will fire off an event jQuery is listening to. This event handler fires off a post to a CFC with the result then logged to the console. Works perfectly. Now let's tweak it just a tiny bit...

<html>

<head> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script> $(document).ready(function() { $("#myButton").click(function() { $.post("test.cfc?method=whatever&returnformat=json", {}, function(res) { console.log('back from cfc'); },"json"); }); });

</script> </head>

<body>

&lt;form method="post"&gt;	
&lt;input type="image" src="meatwork.jpg" id="myButton" value="Click me like you mean it." &gt;
&lt;/form&gt;

</body> </html>

Can you guess what happened here? Try to before scrolling down...






















So - when clicked - if you had your network tools open in Chrome or Firefox, you would see a quick glimpse of a request and then it would go away. Why? The image input type is actually like a submit button. Unlike type=button that does - well - nothing - the image type actually works much like a submit button. What happened was that the entire form posted. Easy to miss especially if you are testing locally. A quick fix is to just prevent the default behavior:

$("#myButton").click(function(e) { e.preventDefault(); $.post("test.cfc?method=whatever&returnformat=json", {}, function(res) { console.log('back from cfc'); },"json"); });

Anyone else ever get bitten by this?

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by todd sharp posted on 4/12/2011 at 9:09 PM

Wow - I'd have never spotted that. I mean, I noticed the src attribute, but I'd not have known it submits the form.

Side note - instead of e.preventDefault() could you not just return false in the click handler?

Comment 2 by Jeremy Battle posted on 4/12/2011 at 9:25 PM

I guessed right!

@todd - I think the general reason to e.preventDefault(); instead of return false; is that e.preventDefault() will not stop event propagation where as returning false will.

I might be wrong, but that is my understanding. In this situation though returning false would work just the same (no other events to propagate)

Comment 3 by Raymond Camden posted on 4/12/2011 at 9:28 PM

@Jeremy - that's my understanding too.

Comment 4 by todd sharp posted on 4/12/2011 at 9:30 PM

Ahh... fantastic - did not know that. Thanks guys.

Comment 5 by Mihai Baboi posted on 4/12/2011 at 10:36 PM

I've had something that's a bit like this. I was firing a .click() function on a check box and it was conflicting with the native click event in the browser. Had a bit of a headache before figuring it out.

Comment 6 by Peter Boughton posted on 4/13/2011 at 1:44 AM

There's another similar problem, if you use the button tag.

Change this code:
<input type="button" id="myButton" value="Click me like you mean it.">

To this:
<button id="myButton">Click me like you mean it.</button>

And you have the same issue.

For some stupid reason, the idiots at the W3C defined the default type for button tag as submit, so to get a non-submitting button you need to specify the type:

<button type="button" id="myButton">Click me like you mean it.</button>

Which is annoyingly repetitive.

Comment 7 by Mike posted on 4/13/2011 at 7:00 PM

Couldn't you also just remove the input type and just have an image with that ID, of course you would have to style it for the pointer but I think it would work the same wouldn't it ?

Comment 8 by Peter Boughton posted on 4/13/2011 at 7:04 PM

It wont work if JS is disabled, whereas with input type=image you can put fallback functionality behind the form submission.

Comment 9 by Rodion Bykov posted on 4/13/2011 at 9:34 PM

Interesting what statistic there is on 'JS disabled'. To me it has no sense in year 201x. I also agree on simpler <img onclick=""> solution.

Comment 10 by Raymond Camden posted on 4/13/2011 at 9:36 PM

Just to be clear - it wasn't so much that there was an easy work around - but that the initial issue was easy to miss. :)

Comment 11 by Edward - Florida SEO posted on 4/15/2011 at 4:06 AM

Here's an apropos link to a great post on event.preventDefault() vs return false ... it simply supports what Jeremy stated and even goes a bit further to show how return false actually fires three bubbling events in it's wake ...

1. event.preventDefault();
2. event.stopPropagation();
3. Stops callback execution and returns immediately when called.

Here's the link for more FYI ...

http://fuelyourcoding.com/j...