Building sites > The enter key
Using the enter key to submit a form
What does the enter button do?
Browser submission behaviors and resulting backend actions
Below are listed the common ways a browser can submit a form in ASP.NET, and the resultant server actions:
-
The form is submitted with no __EVENTTARGET, and no name/value pair for the button. This will result in no event being fired. If you have manually pre-set the __EVENTTARGET, the expected default event will be fired.
-
The client side __doPostBack() event is fired before the form is submitted. This will set the __EVENTTARGET, and fire an event server side.
-
The form is submitted, and the submitting button contributes a name/value pair. This will OVERRIDE any value you have pre-set in the __EVENTTARGET hidden field.
-
The form does not submit.
Form configurations
Below are listed configurations of form that are relevant to this example:
- One text box, one or more <input type=submit> buttons
- Two or more text-boxes, one or more <input type=submit> buttons
- One text box, zero <input type=submit> buttons
- Two or more text-boxes, zero <input type=submit> buttons
Observed browser behaviors:
- PC IE5, 6, form A/C – behavior 1 is observed.
- PC IE5, 6, form B – behavior 3 is observed. The submitting button is the first <input type=submit> button on the page.
- PC IE5, 6, form D – behavior 4 is observed.
- PC NN4.07 – form A/C – behavior 1 is observed.
- PC NN4.07 – form B/D – behavior 4 is observed.
Please contact us if you have tested these conditions with any other browsers.
Remember:
- <asp:Button> controls render as <input type=submit value=xxx> html elements.
- <asp:HtmlInputButton> controls render as <input type=button value=xxx onclick=__doPostBack(...)> html elements.
- <asp:HtmlButton> controls render as <button onclick=__doPostBack(...)>xxx</button>
Summary
The main problem is that IE5/6 will include the name/value pair of the first submit button on the page in the post collection.
There are a couple of ways around this that have been presented in USENET. We discuss these:
What can we do to create a default action when enter is pressed?
Pre-setting __EVENTTARGET
This can be achieved by:
Page.RegisterHiddenField( "__EVENTTARGET", myButton.ClientID );
Where myButton is the button you want to be default.
This method will NOT work when you have <asp:Button> objects on the page. In many browser versions (see above) the Button’s will post automatically, and their name/value pair will override the pre-set __EVENTTARGET.
Also, certain controls will re-set the __EVENTTARGET to an empty string.
Using Cambro.Web.Helpers.TieButton
By using the following code, one can tie a textbox to a button control using javascript.
onkeydown="if ((event.which && event.which == 13) ||
(event.keyCode && event.keyCode == 13))
{document.myForm.myHtmlInputButton.click();return false;}
else return true;"
This function uses javascript to execute the click event of an HtmlInputButton when the enter button is clicked.
We invite discussion of this javascript – is it cross-browser compatible? Please contact us if you have any improvements to share with us.
We’ve created a c# method that adds this code to a specified textbox control for a specified button:
namespace Cambro.Web
{
public class Helpers
{
/// <summary>
/// This ties a textbox to a button.
/// </summary>
/// <param name="TextBoxToTie">
/// This is the textbox to tie to. It doesn't have to be a TextBox control, but must be derived from either HtmlControl or WebControl,
/// and the html control should accept an 'onkeydown' attribute.
/// </param>
/// <param name="ButtonToTie">
/// This is the button to tie to. All we need from this is it's ClientID. The Html tag it renders should support click()
/// </param>
public static void TieButton(Control TextBoxToTie, Control ButtonToTie)
{
string formName;
try
{
int i=0;
Control c = ButtonToTie.Parent;
// Step up the control hierarchy until either:
// 1) We find an HtmlForm control
// 2) We find a Page control - not what we want, but we should stop searching because we a Page will be higher than the HtmlForm.
// 3) We complete 500 iterations. Obviously we are in a loop, and should stop.
while(! (c is System.Web.UI.HtmlControls.HtmlForm) &! (c is System.Web.UI.Page) && i<500)
{
c=c.Parent;
i++;
}
// If we have found an HtmlForm, we use it's ClientID for the formName.
// If not, we use the first form on the page ("forms[0]").
if (c is System.Web.UI.HtmlControls.HtmlForm)
formName = c.ClientID;
else
formName = "forms[0]";
}
catch
{
//If we catch an exception, we should use the first form on the page ("forms[0]").
formName = "forms[0]";
}
// Tie the button.
TieButton(TextBoxToTie, ButtonToTie, formName);
}
/// <summary>
/// This ties a textbox to a button.
/// </summary>
/// <param name="TextBoxToTie">
/// This is the textbox to tie to. It doesn't have to be a TextBox control, but must be derived from either HtmlControl or WebControl,
/// and the html control should accept an 'onkeydown' attribute.
/// </param>
/// <param name="ButtonToTie">
/// This is the button to tie to. All we need from this is it's ClientID. The Html tag it renders should support click()
/// </param>
/// <param name="formName">
/// This is the ClientID of the form that the button resides in.
/// </param>
public static void TieButton(Control TextBoxToTie, Control ButtonToTie, string formName)
{
// This is our javascript - we fire the client-side click event of the button if the enter key is pressed.
string jsString = "if ((event.which && event.which == 13) || (event.keyCode && event.keyCode == 13)) {document."+formName+".elements['"+ButtonToTie.UniqueID+"'].click();return false;} else return true; ";
// We attach this to the onkeydown attribute - we have to cater for HtmlControl or WebControl.
if (TextBoxToTie is System.Web.UI.HtmlControls.HtmlControl)
((System.Web.UI.HtmlControls.HtmlControl)TextBoxToTie).Attributes.Add("onkeydown",jsString);
else if (TextBoxToTie is System.Web.UI.WebControls.WebControl)
((System.Web.UI.WebControls.WebControl)TextBoxToTie).Attributes.Add("onkeydown",jsString);
else
{
// We throw an exception if TextBoxToTie is not of type HtmlControl or WebControl.
throw new ArgumentException("Control TextBoxToTie should be derived from either System.Web.UI.HtmlControls.HtmlControl or System.Web.UI.WebControls.WebControl", "TextBoxToTie");
}
}
}
}
We would also like to invite discussions into this code. Specifically – is there a better method of getting the reference to the HtmlForm control that the button is contained in? This code steps up the control hierarchy until it finds one, however, this is inefficient and un-elegant. Contact us if you have any comments.
Summary
To summarize, the main unwanted behavior is thus:
Pressing enter in a form may be equivalent to clicking the first submit button on the page. If this button is part of another control (ButtonColumn of a DataGrid for example) that event will fire.
What we recommend is that when designing Composite server controls to use HtmlInputButton instead of Button. This will stop the unwanted default clicks.
If you are stuck with a composite control that uses Button's - consider using Cambro.Web.Helpers.TieButton to tie input elements to the default button, or possibly moving your submit Button above the composite control in the rendered html.
When designing a WebForm, if the form has many buttons, one of which is the default, consider using HtmlInputButton instead of Button for all non-default buttons and Button for the default.
If you have several default buttons, each only default when enter is pressed in a specific textbox, consider using Cambro.Web.Helpers.TieButton.
We recommend steering clear of HtmlButton controls. They render as <button> html elements, which are incompatible with Netscape 4.
UPDATE! - Watch out - Various versions of Netscape 4 have a bug where they won't fire the onKeyDown event of the textbox. Read more on google groups
|
Discuss
What do you think of this article? - discuss here.
|
|
Building sites > The enter key |