Asynchronously posting back a form by hitting the Enter key – in ASP.NET WebForms using jQuery

by Oliver 2. August 2012 15:19

On Camping.Info, we lately had a user report that hitting the enter key while in the login form one would be redirected to the search page instead of being logged in. This happened when the focus was still on the password text box because the “Search” button on the page was the first input element on the page (inside the single <form> element that WebForms allows for) of type submit which would by default handle the enter key press event.

To improve the user experience, we set out to find a way to postback the correct UpdatePanel – the one which currently has the focus (or one of its child controls).

Using an ASP.NET Panel and the DefaultButton property

There is a built-in solution to this problem if you’re willing to slightly change your markup and add a hidden <asp:Button> element to your part of the page you want to asynchronously update. You need to wrap your existing html into an <asp:Panel> element and set its DefaultButton property to the ID of that hidden button. This would look something like this:

   1: <div class="form21">
   2:     <asp:Panel runat="server" DefaultButton="btnHiddenRegister">
   3:         <asp:TextBox ID="txtEmail" runat="server" />
   4:         <asp:TextBox ID="txtPassword" runat="server" TextMode="Password" />
   5:         <asp:LinkButton ID="btnRegister" runat="server">Register</asp:LinkButton>
   6:         <asp:Button ID="btnHiddenRegister" runat="server"style="display:none" />
   7:     </asp:Panel>
   8: </div>

Of course, you need to hook up the code-behind Click handler for the btnRegister LinkButton to the hidden Button element as well to make this work.

The proposed solution will instead have html like the following:

   1: <div class="form21 jq-form">
   2:     <asp:TextBox ID="txtEmail" runat="server" />
   3:     <asp:TextBox ID="txtPassword" runat="server" TextMode="Password" />
   4:     <asp:LinkButton ID="btnRegister" runat="server" CssClass="jq-form-submit">Register</asp:LinkButton>
   5: </div>

Let’s see how we get this to work.

Using jQuery

On stackoverflow.com, I quickly found this post about a jQuery replacement for DefaultButton or Link where the this answer points to the original solution from March 2009 proposed by this post on fixing the enter key in ASP.NET with jQuery. I’ve improved on the proposed answer in a few ways, so this is what this post is about.

The original solution

   1: $(document).ready(function(){
   2:     var $btn = $('.form_submit');
   3:     var $form = $btn.parents('.form');
   4:  
   5:     $form.keypress(function(e){
   6:         if (e.which == 13 && e.target.type != 'textarea') {
   7:             if ($btn[0].type == 'submit')
   8:                 $btn[0].click();
   9:             else
  10:                 eval($btn[0].href);
  11:             return false;
  12:         }
  13:     });
  14: });

Remarks: works only if the content is present at the time the script executes, and works only for a single pair of form and form-submit elements.

Our improved solution

   1: $('body')
   2:   .off('keypress.enter')
   3:   .on('keypress.enter', function (e) {
   4:     if (e.which == 13 && e.target.type != 'textarea') {
   5:       var $btn = $(e.target).closest('.jq-form').find('.jq-form-submit');
   6:       if ($btn.length > 0) {
   7:         if ($btn[0].type == 'submit') {
   8:           $btn[0].click();
   9:         }
  10:         else {
  11:           eval($btn[0].href);
  12:         }
  13:         return false;
  14:       }
  15:     }
  16:   });

Improvements

The first thing to improve is the registration of the keypress event handler. Since Camping.Info is quite a dynamic site with lots of asynchronous postbacks to the server (mostly using WebForms’ UpdatePanels) a lot of the javascript code we need on our page won’t execute properly as is because it expects the elements it works with to be present at the time of the script’s execution. That’s also the case with the original solution: both the submit button element with class .form_submit and the pseudo-form element .form (I’ve called it pseudo-form element since it’s just a parent element of any type marked with the class .form) must be present when the script executes, otherwise nothing will happen. That’s why – using jQuery 1.7 syntax – we register the keypress event handler NOT on the pseudo-form element but directly on the body using on(). We also the event namespace it by appending .enter to its name keypress so that we can safely remove it (using off()) in case we call the script a second time during postback to prevent it from being attached twice. Please note, that at this point neither the pseudo-form nor the form submit element must be present on the page for this to work.

Once the enter key has been pressed anywhere on the page and we’re inside the event handler, we set out to check for a pseudo-form surrounding the element that received the enter key press event and inside it we look for a submit element. [I’ve also changed the class names for those elements by our internal convention to prefix all those that are jQuery related by jq- to set them apart from the CSS class names our designer works with.] Only if we’ve found both those elements, we proceed with either clicking the element if it’s really a button or executing the javascript code that ASP.NET rendered into our LinkButton’s href tag which asynchronously posts back to the server for some update to our page.

A subtle but important detail here is to return false (and thus prevent the event from being processed any further) only in case we actually found the pseudo-form and submit elements, so that in the opposite case the default behavior of the page will be preserved.

Conclusion

The solution presented here works equally well with static and dynamically loaded page content and for any number of forms on your page. It replaces the solution provided by ASP.NET WebForms’ using a Panel and its DefaultButton property, resulting also in cleaner markup.

Happy Coding!

Comments are closed

About Oliver

shades-of-orange.com code blog logo I build web applications using ASP.NET and have a passion for javascript. Enjoy MVC 4 and Orchard CMS, and I do TDD whenever I can. I like clean code. Love to spend time with my wife and our children. My profile on Stack Exchange, a network of free, community-driven Q&A sites

About Anton

shades-of-orange.com code blog logo I'm a software developer at teamaton. I code in C# and work with MVC, Orchard, SpecFlow, Coypu and NHibernate. I enjoy beach volleyball, board games and Coke.