This time the problems I found were exposed with Firefox but the real problem was in the web app code even if the browser behavior was surprising.
The app is doing two interesting things with buttons. It disables the buttons before it submits a form and it has some buttons that work like a link by setting location.href. My goal was to simply change the button style and not other functionality so I just changed <input type=’button’…> to <button …>.
Here is a reproducer that captures the essence of what the app is doing. The actual app uses the post method and does useful stuff.
... <p>Doesn't work on Firefox 2</p> <form id="f1" method="get" action="http://hardlikesoftware.com/weblog/"> <label for="someinput">Label:</label> <input type="text" value="foo" id="someinput"> <button id="b1" onclick="this.disabled=true;document.forms.f1.submit();"> Disable and Submit </button> </form> <p>Doesn't work on Firefox 3 - here the button works like a link</p> <form id="f2" method="get" action="http://hardlikesoftware.com/weblog/"> <label for="someinput2">Label:</label> <input type="text" value="bar" id="someinput2"> <button id="b2" onclick="this.disabled=true;self.location.href='http://www.google.com'"> Goto </button> </form> ...
The expected behavior is that the “Disable and Submit” button will take you to the HardLikeSoftware main page and the “Goto” button will take you to google. On Firefox 2 the first button gets disabled and no request of any kind is sent. The second button works fine. On Firefox 3 the first button works as desired but the second button submits the form and you end up at the HLS main page. The problem goes away if you use IE7, Opera, or Safari (I suspect IE6 also works), or change the button elements to input buttons, or move the buttons outside of the form. If you don’t disable the buttons then the first button works in both Firefox 2 and 3 but the second button doesn’t work in either.
It was the behavior of the second button that finally tipped me off when I realized that it was actually submitting the form. Noticing this was more difficult with the actual app simply because of the way it works.
The code had been getting away with not returning true or false from the click handler for a long time. Simply adding “return false; to the event handlers solves all the problems and continues to work in the other browsers. Returning false from the click event means don’t take the default action. For a submit button the default action is to submit the form.
Another aspect to this issue is that when you use the input element to create a button you make a conscious choice between a submit button and a regular button. But when you use the button element it is a submit button by default. Thanks to IE the default isn’t a very useful default because you can’t use it this way.
The moral of the story is always return an appropriate value from an event handler. Also it may not be a bad idea to be specific about they type of button. Although it looks redundant <button type=’button’> may be the way to go.