Link to home
Start Free TrialLog in
Avatar of jjamjatra
jjamjatra

asked on

How to let user hit ENTER key after typing username then password

I am all wrapped up in using some new facilities of ASP.NET 2.0 and I feel very confused about how to accomplish this.
I have the basic code working now but I want to have the page submitted automatically when the user has finished
typing the password and simply hits the ENTER key. Should be simple I think but I have a lot pieces here
(code snippets follow):

First, I have a content page (referencing a master page) which includes multiple user controls. One usercontrol has a textbox for entering a zipcode and a button which displays a report when the button is clicked. The other usercontrol has textboxes for entering username and password and a button which handles login processing when clicked. Both usercontrols face the same challenge with the ENTER key; for simplicity, the snippets below relate to the latter user control only:

<%@ Page Language="VB" MasterPageFile="~/Home.master" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default"%>
<%@ Register Src="UILayer/UserControls/LoginMechanism.ascx" TagName="LoginMechanism" TagPrefix="uc1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
...then further down in the content page
<asp:TableCell VerticalAlign="Top">
      <uc1:LoginMechanism id="LoginMechanism1" runat="server">
      </uc1:LoginMechanism><br />
</asp:TableCell>
       
Secondly, inside the usercontrol, here are the webcontrols of interest:

<td>
      <asp:TextBox ID="Password" runat="server" TextMode="Password"></asp:TextBox>
        <asp:RequiredFieldValidator ID="PasswordRequired" runat="server" ControlToValidate="Password"
               ErrorMessage="Password is required." ToolTip="Password is required."
               ValidationGroup="ctl00$ctl05$Login1">*
      </asp:RequiredFieldValidator>
</td>
<td>
       <asp:Button ID="LoginButton" runat="server"
         CommandName="Login" UseSubmitBehavior="true"
         Text="Log In" ValidationGroup="ctl00$ctl05$Login1" />
</td>

In the code-behind of the usercontrol, I have this code working to place the focus on the button when the page loads:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
      Dim sControlName As String = "ctl00_ContentPlaceHolder1_LoginMechanism1_LoginView1_Login1_LoginButton"
      Page.ClientScript.RegisterStartupScript(Me.GetType(), "Key1", "<script>document.getElementById('" & _
          sControlName & "').focus();</script>")
End Sub                 

But of course as soon as I (the user) move to the textboxes for username and password the focus is changed.
I think what I really need is a way to detect that after typing the password the ENTER key is pressed. Or to
rephrase this, how to I "connect" an ASP:Textbox to a particular ASP:Button such that finishing with the
data entry into the button by hitting ENTER causes the desired ASP:Button to automatically clicked?



Avatar of ethoths
ethoths

Try this...

Page.RegisterHiddenField("__EVENTTARGET", "btnSearch")
(asp.net 1.1)

or better still this...

<form defaultbutton=“button1” runat=“server”>
(asp.net 2.0)
You can try this, it's simple but works on my web pages, but I'm
not using Master pages so I'm not sure if it will work.

Use the "TextChanged" event for the textbox
When text is typed in the textbox, the code will fire for that textbox.


In the code-behind of your usercontrol add this:

Private Sub Password_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Password.TextChanged

  ' and add your code for LoginButton here  

End Sub
Avatar of jjamjatra

ASKER

Thanks for responding. Trying your suggestion, here is more code related to this (still having problems):

Imports System.Web
Partial Class _LoginMechanism
    Inherits System.Web.UI.UserControl
    Public WithEvents password As Button                   'I added this in order to alllow for handles below per your suggestion
           
    Private Sub Password_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles password.TextChanged
        ' and add your code for LoginButton here  
    End Sub

I am getting a compile error (squiggley line) under .TextChanged which says "Event textchanged cannot be found".

Moreover, I am not sure what you mean "add your code for LoginButton here". I want it to "auto-click" the button; not sure how to cause that.
try adding this:
Protected WithEvents Password As System.Web.UI.WebControls.TextBox
instead of:
Public WithEvents password As Button
Thanks Mike...
that solved that part of the problem.

What did you mean for "add your code for LoginButton here". I want it to "auto-click" the button; not sure how to cause that.
Mike,

I found this and I am researching putting it in to handle the problem:

http://jennifermadden.com/javascript/stringEnterKeyDetector.html

Thanks for your time. Is there a better way to do this in pure ASP.NET without Javascript?
I'm not sure what the problem is. You say you want to type some text into a text box then then when the user hits the enter key for the form to be submitted. This is precisely why you have the "defaultbutton" attribute on the form element! It's taylor made for purpose this and only takes about 3 seconds to implement. What's the problem?


Here is the complete mark-up as an example...

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>
            Default Button Demo
        </title>
    </head>
    <body>
        <form id="form1" defaultbutton="Button2" runat="server">
            <asp:textbox runat="server" />
            <asp:Button ID="Button1" runat=server Text="Button 1" OnClientClick="alert('Button 1')" />
            <asp:Button ID="Button2" runat=server Text="Button 2" OnClientClick="alert('Button 2')" />
        </form>
    </body>
</html>
PS If you don't want to see the button on the form (can't think why you'd want that) then use this..

<asp:Button ID="Button2" runat=server Text="Button 2" OnClientClick="alert('Button 2')" style="visibility:hidden; />

for the submit button.
Thank you for your interest and help.
Long ago in my research I came across the simple defaultButton approach. Unfortunately, because of some of the other new things I've used I think it is not that easy. Note that I am using a master page (which is the only file with <body  and <form elements. So I have one form in the master page.

Most of my post describes the content page (which depends on this master page).

The content page includes 2 user controls. I've chosen to describe the details of the "login mechanism" which is a textbox for username, textbox for password and a login button (the other user control has the same issue; it has a textbox for zipcode and a submit button).

So hopefully you can see that at the form level or master page level there is no way I could even choose which should be the "default button". Reason: it depends on which textbox is "active" when the ENTER key is hit.

To satisfy myself however, I did try your simple approach and I placed this in my master page:

 <form id="formMaster" defaultButton="LoginButton" runat="server">

I get a Server error in my app:

The DefaultButton of 'formMaster' must be the ID of a control of type IButtonControl.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The DefaultButton of 'formMaster' must be the ID of a control of type IButtonControl.

But I think even if I get around this, I cannot "choose" a default button given my setup of this with user controls.


>> What did you mean for "add your code for LoginButton here". I want it to "auto->>click" the button; not sure how to cause that.

I don't know what auto-click is. Is this something new to VS 2005?

What I meant by "add your code..." was to put the code that runs
after the button below is clicked in the "TextChanged" event.

<asp:Button ID="LoginButton" CommandName="Login" Text="Log In"
  UseSubmitBehavior="true"   ValidationGroup="ctl00$ctl05$Login1" />

What code is run after the "LoginButton" is clicked?
I've been researching and I found this blog entry that pretty much matches what I am trying to do:

http://www.2404.co.uk/index.php?path=articles/view.php&articleId=18

So I've tried to implement this and I am not hooking into the keypress event properly (i.e. nothing happens). Here are the top few lines of my .ASCX file (note the new Javascript function):

<%@ Control Language="VB" AutoEventWireup="false" CodeFile="LoginMechanism.ascx.vb" Inherits="_LoginMechanism" %>
<script language="javascript">
function formSubmit(event, button)
{
    debugger
      if(event.keyCode == 13)
      {
            document.getElementById(button).click();
            return false;
      }
}
</script>
Here are the top few lines of the code behind file for the user control:

Imports System.Web
Partial Class _LoginMechanism
    Inherits System.Web.UI.UserControl

    Protected WithEvents Password As New System.Web.UI.WebControls.TextBox                                        'I am guessing on this declaration !
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        ' add login form key press events
        Password.Attributes.Add("onkeypress", "return formSubmit(event,'LoginMechanism1_LoginButton');")

If I take out the NEW from:
    Protected WithEvents Password As New System.Web.UI.WebControls.TextBox                                        
...it blows up with:
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

Source Error:


Line 6:      Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Line 7:          ' add login form key press events
Line 8:          Password.Attributes.Add("onkeypress", "return formSubmit(event,'LoginMechanism1_LoginButton');")
Line 9:          'Password.Attributes.Add("onKeypress", "checkEnter(event);")
Line 10:         'Dim sControlName As String = "ctl00_ContentPlaceHolder1_LoginMechanism1_LoginView1_Login1_LoginButton"
 

Source File: c:\inetpub\wwwroot\ITMO_BackupMDWEB\UILayer\UserControls\LoginMechanism.ascx.vb    Line: 8
Thanks for taking the time to reply jjamjatra.

It is possible to access the master page and also the controls (including the form) from the code behind file. However, since you want a different action depending on where the cusror is at the time the enter button is hit then my solution will not  work. By design you can only have one default button per page.

Another possibility is to use the defaultbutton attribute as applied to an asp.net  panel, I've not used it myself but I belive it will do what you want if you can arrange all you submit buttons in different panels. It would be nice if it did work since it's such an elegant answer.
Actually it does work...

            <asp:Panel DefaultButton="Button1" ID="pan1" runat=server>
                <asp:textbox ID="Textbox1" runat="server" />
                <asp:Button ID="Button1" runat=server Text="Button 1" OnClientClick="alert('Button 1')" />
                <asp:Button ID="Button2" runat=server Text="Button 2" OnClientClick="alert('Button 2')" />
            </asp:Panel>
            <br/>
            <br/>
            <asp:Panel DefaultButton="Button4" ID="Pan2" runat=server>
                <asp:textbox ID="Textbox2" runat="server" />
                <asp:Button ID="Button3" runat=server Text="Button 3" OnClientClick="alert('Button 3')" />
                <asp:Button ID="Button4" runat=server Text="Button 4" OnClientClick="alert('Button 4')" />
            </asp:Panel>
To MikeMCSD:
>> What did you mean for "add your code for LoginButton here". I want it to "auto->>click" the button; not sure how to cause that.
>I don't know what auto-click is. Is this something new to VS 2005?
>What I meant by "add your code..." was to put the code that runs
>after the button below is clicked in the "TextChanged" event.

<asp:Button ID="LoginButton" CommandName="Login" Text="Log In"
  UseSubmitBehavior="true"   ValidationGroup="ctl00$ctl05$Login1" />

>What code is run after the "LoginButton" is clicked?

Mike,
I only wrote "auto-click" as a shorthand; sorry not more precise. In short, I want to automatically submit the form when the user hits enter after typing in a textbox. Please see above for more detail about the problem.

To answer your question back to me about "What code is run after the "LoginButton" is clicked?", all I can describe is that I am using a profile provider to handle logins:
<profile enabled="true" defaultProvider="StoredProcedureProfileProvider">
      <providers>
        <clear/>
        <!--
        <add name="TableProfileProvider"
                         type="Microsoft.Samples.SqlTableProfileProvider"
                         connectionStringName="TestDatabase"
                         table="MemberProfile"
                         applicationName="/"/>
        -->
        <add name="StoredProcedureProfileProvider"
                 type="Microsoft.Samples.SqlStoredProcedureProfileProvider"
                 connectionStringName="TestDatabase"
                 setProcedure="setCustomProfileData"
                 readProcedure="getCustomProfileData"
                 applicationName="/"/>
      </providers>
I have the source for this in my App_Code directory but I've sort of treated it as a "black box" - it works and is in C#. Please understand that all of this works fine if the LoginButton is explicitly clicked. I am trying to associate the hitting of ENTER with the "click" of the LoginButton. ethoths comment above has given me a fresh idea I will explore tomorrow.
Thanks to both of you for helping me chase this down. Goodnight from Fairfax Va. - it is now 6:35pm and I am hungry and leaving.
See what happens when you add the line below:

Private Sub Password_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles password.TextChanged
        ' and add your code for LoginButton here  

         LoginButton.PerformClick()         <<<<<<<<<<<<<<<

End Sub
I think the above only working with Windows programs,
use this instead:

LoginButton_Click(nothing, nothing)
Hi Mike,

Here is what I added to my usercontrol.aspx.vb file to try your approach:

Protected WithEvents LoginButton As System.Web.UI.WebControls.Button
Protected WithEvents Password As New System.Web.UI.WebControls.TextBox   'NOTE - without NEW I get "Object reference not set to an instance of an object"

Private Sub Password_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Password.TextChanged
        ' and add your code for LoginButton here  
        LoginButton_Click(Nothing, Nothing)
End Sub
Private Sub LoginButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles LoginButton.Click
        Dim i As Integer
        i = 0
        Return
End Sub

I had breakpoints in Page_Load which were hit. I had breakpoints on each of the above two SUBs and the event handlers above were never reached. That is, I entered username and password and hit enter. The logon never gets processed.
I found this and I am pursing it:

http://www.spaanjaars.com/QuickDocId.aspx?QUICKDOC=374

Please take a look. I think this will work for me but I am confused how to address my LoginButton deep inside my usercontrol.

For example, spaanjaars suggests:

Page.Form.DefaultButton = LoginButton.UniqueID

...but I cannot get away with in the Page_Load in my usercontrol.ascx.vb file because I get the complaint: "Name 'LoginButton' is not declared"

When I try to get help with Intellisense, I run out to the end of the object model when I type:

 Page.Form.DefaultButton = Me.LoginView1.AnonymousTemplate.

There is an <ASP:Button called LoginButton in there but I do not know the syntax for properly pointing to it. Could you suggest how to get at it with this approach?
Setting the defaultbutton programatically (rather then declartively as per my previous suggestion)  can be done as spaanjaars suggests but you should probably use the FindControl function to locate the button.
I will research the FindControl function. I tried declaratively as you suggested and got this error:

The DefaultButton of 'pan1' must be the ID of a control of type IButtonControl

Here is a snippet of what I added per your suggestion:

<asp:Panel DefaultButton="LoginButton" ID="pan1" runat=server>
      <asp:LoginView ID="LoginView1" runat="server">
      <AnonymousTemplate>
             <asp:Login  ID="Login1" runat="server" BackColor="#F7F6F3" BorderColor="#E6E2D8" BorderPadding="4"
               <LayoutTemplate>
               <td align="right" colspan="2">
                   <asp:Button UseSubmitBehavior="true" TabIndex="3" ID="LoginButton" runat="server"
                        Text="Log In" ValidationGroup="ctl00$ctl05$Login1" />
               </td>
                <a href="CreateAccount.aspx">Create a new account</a><br />
      </AnonymousTemplate>
      </asp:LoginView>
</asp:Panel>
Yes the problem is that the Login control is a naming container and adds things like ctl00$ctl05$ to the id. That is what findcontrol is designed to get around. You might need to call is recursivly to get into the user control though.

Just a not of warning though. I see one of you controls has an attribute of ValidationGroup="ctl00$ctl05$Login1". Note that the ct100... bit is determined by the runtime and may change if you add or move controls to the page.


Boy this is difficult stuff. Here is the latest code inserted at the top of my usercontrol.ascx.vb:

Imports System.Web
Partial Class _LoginMechanism
    Inherits System.Web.UI.UserControl
   
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim myButt As Button
        myButt = Page.FindControl("LoginButton")
        If Not myButt Is Nothing Then
            Response.Write("Found LoginButton on User Control")
            Page.Form.DefaultButton = myButt.UniqueID
        End If

        Dim b As Button = Me.LoginView1.FindControl("LoginButton")
        If Not b Is Nothing Then
            Response.Write("Found LoginButton on User Control")
            Page.Form.DefaultButton = b.UniqueID
        End If

Neither technique works (compiles OK and runs without error but FindControl always returns nothing and hence I cannot get the DefaultButton set. Remember this is one of 2 usercontrols that have been added to a content page that is in a contentplaceholder of a master page.
The problem is the naming containers. Each user control adds it own CT???$ to the id of the button to make it unique on the page. You can either call the FindControl recursivley (the best way) or walk it down if you know the control hirearchy...

Recursivley...
(rought outline)

Public FindControlRecursive(byval ctl as control, byval id as string) as control
    If not FindControl(id) is nothing then
      return FindControl(id)
    else
        If ctl.hascontrols then
            for each subCtl as control in ctrl.controls
                FindControlRecursive(subCtl, id)
            next
        end if
    end if
return nothing
end sub

Walking the hirearchy...

Me.Page.FindControl("UC1").FindControl("UC2").FindControl("Button").

This assumes that the button is a member of UC2 which is a member of UC1. This will work but will break if you alter your control hirearchy. You shoud get the idea.

Hi - thanks again for your interest and help. Here is my latest attempt based on your suggestion:

Imports System.Web
Partial Class _LoginMechanism
    Inherits System.Web.UI.UserControl
Public Function FindControlRecursively(ByVal ctl As Control, ByVal id As String) As Control
        If Not FindControl(id) Is Nothing Then
            Return FindControl(id)
        Else
            If ctl.HasControls Then
                For Each subCtl As Control In ctl.Controls
                    FindControlRecursively(subCtl, id)
                Next
            End If
        End If
        Return Nothing
End Function

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim b As Button = FindControlRecursively(Me, "LoginButton")
        If b IsNot Nothing Then
            Page.Form.DefaultButton = b.UniqueID
        End If
....etc.

This code is close - I think - because I have debugged it line by line and it properly looks through all the controls in this user control ("Me") and yet when it gets to LoginButton it does not "find" it but skips right over it, continuing through the control collection and eventually returns nothing.
If it's skipping over this contol but finding it's siblings then there is something odd about the contol. Try it with a regular button and no attributes (except runat and id).
OK - I stripped the control of all the stuff it had:

<asp:Button UseSubmitBehavior="true" TabIndex="3" ID="LoginButton" runat="server" BackColor="#FFFBFF" BorderColor="#CCCCCC"
   BorderStyle="Solid" BorderWidth="1px" CommandName="Login" Font-Names="Verdana"
   Font-Size="0.8em" ForeColor="#284775" Text="Log In" ValidationGroup="ctl00$ctl05$Login1" />

and established it as follows:

<asp:Button ID="LoginButton" runat="server" Text="Log In"/>

Same behavior in the recursive loop (skips right over this button and all its siblings...)

Moreover, by removing the other attributes, now an explicit click of this button seems to ignore or bypass login processing. Maybe it has to have CommandName="Login" for the membership provider or something...

I found an interesting blog entry that suggests the presence of validator controls might be a problem:

see http://www.spaanjaars.com/QuickDocId.aspx?quickdoc=379 (especially the UPDATE NOTE dated 01-15-2006).
to ethoths:

Please note my comment above. I think there IS something odd about the control - but I don't know what else to do or try. Imar Spaanjaars, I think, suggested that my user control needs to be rebuilt. If I read him correctly, he says the LoginView should not be part of the UserControl. I think he is telling me that the UC should contain the Login control only. Then, I guess, the various FindControl routines will work. BUT - I don't understand why constructing a usercontrol like I have is "wrong" (again, everything works correctly as long as the Login button is explicitly clicked). Please comment on this setup. Right now I have in the user control:

<asp:LoginView ID="LoginView1" runat="server">
<AnonymousTemplate>
       <asp:Login  ID="Login1" runat="server">
                     <LayoutTemplate>
                                        <asp:Button UseSubmitBehavior="true" TabIndex="3" ID="LoginButton" runat="server" BackColor="#FFFBFF"                     BorderColor="#CCCCCC"
                                           BorderStyle="Solid" BorderWidth="1px" CommandName="Login" Font-Names="Verdana"
                                           Font-Size="0.8em" ForeColor="#284775" Text="Log In" ValidationGroup="ctl00$ctl05$Login1" />
                     </LayoutTemplate>
      </asp:Login>
          <a href="CreateAccount.aspx">Create a new account</a><br />
</AnonymousTemplate>
                    <LoggedInTemplate>
...etc.
                    </LoggedInTemplate>
                </asp:LoginView>
Imar helped me get further on this but I fear I am still stuck. Here are the comments I posted to:
http://www.spaanjaars.com/QuickDocId.aspx?quickdocid=379

 Thank you so much, Imar. I did as you said reworked it. Here is the code that works (not too bad in hindsight):

Dim myLogin As Login = CType(Me.LoginView1.FindControl("Login1"), Login)
If myLogin IsNot Nothing Then
  Dim myButton As Button = CType(myLogin.FindControl("LoginButton"), Button)
  If myButton IsNot Nothing Then
          Me.Page.Form.DefaultButton = myButton.UniqueID
  End If
End If

This now means the user can hit ENTER after typing password and the Login button will be fired. Good news! BUT -
I believe I have the same problem as you describe at the very top. Just like your Search textbox and button and QuickDocID textbox and button, I have the username and password textboxes and LoginButton in this US plus (in a different user control) I have a ZipCode textbox and Button (text="Find").

It is for these reasons I thought I recognized an identical problem as you described with your Go buttons and I think I need clientside Javascript to detect the keypress of ENTER key, etc.
And yet, I think you have said that will not work asp:RequiredFieldValidator  controls in the control collection.
Thanks to Imar at http://www.spaanjaars.com/QuickDocId.aspx?quickdocid=379 I now have a complete solution to this issue. In my LoginMechanism.ascx user control I have the following:

        Dim myLogin As Login = CType(Me.LoginView1.FindControl("Login1"), Login)
        If myLogin IsNot Nothing Then
            Dim myButton As Button = CType(myLogin.FindControl("LoginButton"), Button)
            If myButton IsNot Nothing Then
                Me.Page.Form.DefaultButton = myButton.UniqueID
                Dim myFoundTextBox As TextBox = CType(myLogin.FindControl("Password"), TextBox)
                myFoundTextBox.Attributes.Add("onclick", "document.forms[0].onkeypress = " _
                + "new Function(""return WebForm_FireDefaultButton(event, '" + myButton.UniqueID + "');"");")
            End If
        End If

And in my FindZipCodeNearYou.ascx user control I have the following:

        Dim myButton As Button = CType(Me.FindControl("btnFind"), Button)
        If myButton IsNot Nothing Then
            Me.Page.Form.DefaultButton = myButton.UniqueID
            Dim myFoundTextBox As TextBox = CType(Me.FindControl("txtZipCode"), TextBox)
            myFoundTextBox.Attributes.Add("onclick", "document.forms[0].onkeypress = " _
            + "new Function(""return WebForm_FireDefaultButton(event, '" + myButton.UniqueID + "');"");")
        End If

Both of these user controls are used on the same content page within a master page. Now in either textbox above, the user can type his password (or zipcode) and immediately hit the ENTER key and the proper button will be fired. This problem can be closed.
ASKER CERTIFIED SOLUTION
Avatar of Computer101
Computer101
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial