Fixing the enter key in ASP.NET with jQuery
4 Mar 2009One of the fundamental problems with ASP.NET WebForms is the fact that you can only have one form per page. This jumps up and bites you when you have a set of fields and a button and you want the enter key to submit the form.
In ASP.NET 2.0 they came out with a "fix" for this. You can wrap your fields in a Panel and set the default button:
<asp:Panel ID="_pnlLogin" DefaultButton="_btnLogin" runat="server">
UserName: <asp:TextBox ID="_txtUserName" runat="server" />
Password: <asp:TextBox ID="_txtPassword" runat="server" />
<asp:LinkButton ID="_btnLogin" Text="Login" runat="server"/>
</asp:Panel>
Some of you will know limitation here. This works with a Button, but not a LinkButton. Let's see why. Here is the resulting HTML:
<div id="_pnlLogin" onkeypress="javascript:return WebForm_FireDefaultButton(event, &#x27;_btnLogin&#x27;)">
UserName: <input name="_txtUsername" type="text" id="_txtUsername" />
Password: <input name="ctl00$mainContent$_txtPassword" type="text" id="_txtPassword" />
<a id="_btnLogin" href="javascript:__doPostBack('_btnLogin','')">Login</a>
</div>
The Panel renders as a div, and on any key pressed will call WebForm_FireDefaultButton:
function WebForm_FireDefaultButton(event, target) {
if (!__defaultFired && event.keyCode == 13 && !(event.srcElement && (event.srcElement.tagName.toLowerCase() == "textarea"))) {
var defaultButton;
if (__nonMSDOMBrowser) {
defaultButton = document.getElementById(target);
} else {
defaultButton = document.all[target];
}
if (defaultButton && typeof(defaultButton.click) != "undefined") {
__defaultFired = true;
defaultButton.click();
event.cancelBubble = true;
if (event.stopPropagation) event.stopPropagation();
return false;
}
}
return true;
}
This method checks for the enter key and then calls click on the default button. All good except for one thing: the LinkButton renders as an "a" tag. Anchor tags don't have a click() method unfortunately. At least not in Firefox.
So let's fix it! I've recently been reading "Learning jQuery" which is a great book on this cool javascript library. I'll use jQuery instead of straight javascript as it is much easier to write cross browser code and it's a lot more concise. Plus there are heaps of plugins for it, and it's a pretty small download for your page.
I want to improve the markup of my page at the same time so I'll try to minimise the amount of server controls I use and get rid of that inline javascript call. My new aspx looks like this:
<div class="form">
UserName: <asp:TextBox ID="_txtUsername" runat="server" />
Password: <asp:TextBox ID="_txtPassword" runat="server" />
<asp:LinkButton ID="_btnLogin" Text="Login" runat="server" CssClass="form_submit"/>
</div>
So if I have a div with the class "form", the default submit button is the first element with the "form_submit" class. Nice, simple and unobtrusive.
Here's the javascript I ended up with:
$(document).ready(function(){
var $btn = $('.form_submit');
var $form = $btn.parents('.form');
$form.keypress(function(e){
if (e.which == 13 && e.target.type != 'textarea') {
if ($btn[0].type == 'submit')
$btn[0].click();
else
eval($btn[0].href);
return false;
}
});
});
Basically it's going to find any .form_submit elements, find a parent form, and add a keypress handler for the form. When the keypress is triggered, if it's the enter key and we're not in a textarea, we'll click the default submit button if it IS a button, if it's a link we'll Eval the href attribute, which is going to be our javascript postback call.
Cool, I can keep it tucked away in an js file include, and i've improved my markup.