How Do I Dynamically Switch the DefaultButton at Run-Time?

In a previous article I showed you how to use the ASP.NET 2.0 DefaultFocus and DefaultButton features inside a Master Page. You saw how you could use the UniqueID of a control to pass the right control ID to the WebForm_AutoFocus JavaScript method. In this short article, I'll show you how you can use another client side script method to dynamically switch the DefaultButton at run-time.

Update!! 01-15-2006
I just tried this concept in a larger application using validator controls, and then things seems to break. Somehow, the validator controls and switching the DefaultButton dynamically don't play nice together. I haven't yet found a work-around, but if you know a way to fix this, please let me know.

Introduction

It's not uncommon that your page contains multiple text boxes and buttons that should each fire different events at the server. For example, consider the two boxes at the top of my web site. The first Go button should fire a search action with the search term entered in the first text box. The second button should take you directly to an article specified by a Quick Doc ID in the second text box.

Most users will fill in one of the two text boxes, simply hit enter and then expect the proper action to be carried out. But in my current site (built with .NET 1.1) this is not the case. (Try it and you'll see what I mean). If you enter a search term and hit enter, you go to the search page. However, if you enter a Quick Doc ID and hit enter, nothing happens.

The new DefaultButton from ASP.NET 2.0 is a welcome addition in that it allows you to specify the button that must be "clicked" when you hit enter. However, in the scenario described above, this is not enough. If I am typing a search term, I want the first Go button to be the DefaultButton and if I am entering a Quick Doc ID I want the second button to be the DefaultButton.

Attributes to the Rescue

Fortunately, switching what button is considered the default button at run-time isn't too difficult. If you look at the source of a page that has the DefaultButton set up, you'll see something similar to the following in the <form> tag:

<form name="form1" method="post" action="SomePage.aspx" 
     onkeypress="javascript:return WebForm_FireDefaultButton(event, 
     'Button1')" id="form1"
>

As you can see, all this code does is call a method called WebForm_FireDefaultButton and pass it up the event that triggered the initial action and the unique ID of a control. You can use this knowledge to change the DefaultButton from JavaScript at run-time. The simplest way to use this, is to call this method in the onclick event of a text box. You can add these onclick handlers through code using the controls Attributes collection. For example, in my new ASP.NET 2.0 version of this web site, I added the following code in the Page_Load event of the user control that has the search and the Quick Doc ID buttons:

txtQuickSearch.Attributes.Add("onclick",
   "document.forms[0].onkeypress = "
   + "new Function(\"return WebForm_FireDefaultButton(event, '" 
   + btnQuickSearch.UniqueID + "');\");");

txtQuickDocId.Attributes.Add("onclick",
   "document.forms[0].onkeypress = "
   + "new Function(\"return WebForm_FireDefaultButton(event, '" 
   + btnQuickDocId.UniqueID + "');\");");  

Whenever you click the search text box, onclick is fired and WebForm_FireDefaultButton is called. This method is then passed the unique ID of the appropriate button. The same applies to the Quick Doc ID button: when you click it, WebForm_FireDefaultButton is called and the DefaultButton is switched again.

The only thing you need to watch out for is that you need to set the DefaultButton at least once in your page using "normal" ways (as an attribute on the <form> tag for example, or through code as shown in my article about DefaultButtons in master pages). If you don't do this, ASP.NET won't inject the <script> tag that retrieves the required JavaScript code (including WebForm_FireDefaultButton) from the server.


Where to Next?

Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .


Consider making a donation
Please consider making a donation using PayPal. Your donation helps me to pay the bills so I can keep running Imar.Spaanjaars.Com, providing fresh content as often as possible.



Feedback by Other Visitors of Imar.Spaanjaars.Com

On Friday, November 03, 2006 4:42:17 PM John Adams said:
I am chasing this exact problem and I'm very grateful for your suggestions. I am currently working on this but I notice that on this very site it does NOT behave the way you would like. That is, I type in a quickdocid of 374 and hit enter and it comes to the search page (not 374). I have to explicity click the GO button to the right of the quickdocid textbox to get it to work properly. So have you NOT implemented this for your site or is this the case where you say it is "broken" due to the presence of validator controls.

I am using Firefox 1.5.0.7 and IE 6 and they both fail to behave the way you and I would like them to behave on this very page. Hope you can clarify for me because I am facing the same exact challenge.
On Saturday, November 04, 2006 8:53:49 AM Imar Spaanjaars said:
Hi John,

You're right. My site currently doesn't use the default button stuff because I have a number of validators that cause problems. (The QuickDocId box is checked for a valid number).

I think one way to overcome this is to use server side validation only. Not very user friendly but it might work. I haven't actually implemented that in my site, but it may work for you.

Cheers,

Imar
On Saturday, November 04, 2006 2:52:54 PM John Adams said:
Thank you for confirming this. I would love know a bit more if you could describe what you learned about "validators that cause problems" because I think I am similarly stuck and I know far less than you. I am using the new Login control of ASP.NET 2.0 which expands into ASP:TextBox, ASP:RequiredFieldValidator, ASP:Button, etc. I have tried so many different techniques to support detection of the ENTER key leading to "automatic submission" of the form it is confusing to summarize where I currently stand. Not sure if you will want to or be able to read this url where my problem and code snippets are shown:

http://www.experts-exchange.com/Programming/Programming_Languages/Dot_Net/ASP_DOT_NET/Q_22045489.html

My masterpage and my usercontrol (containing this rather complex Login control) have complicated efforts to use FindControl in an attempt to use .Attribute.Add for onKeyPress as described by you.

But I would like to learn more if possible that I may be running toward a "dead end" where nothing will work. Hence if you could elaborate any more on if the presence of my RequiredFieldValidator controls is what is causing all these problems. Are there any Knowledge Base entries that acknowledge and describe this problem more that you know of? Thanks for your contributions on this to me. Cheers, John
On Saturday, November 04, 2006 10:59:01 PM Imar Spaanjaars said:
Hi John,

I need to register to see the post you pointed to, so I haven't looked at your code.

However, usually you should be able to do something like this in a User Control:

Dim myButton As Button = CType(Login1.FindControl("LoginButton"), Button)
Me.Page.Form.DefaultButton = myButton.UniqueID

You should note that the problems I had described above are related to *dynamically* switching the DefaultButton at runtime, through JavaScript.

That's different from setting it at run-time with the code above. I never had problems with that, even with UCs in a Master Page.

Cheers,

Imar
On Monday, November 06, 2006 8:32:28 PM John Adams said:
Thanks Imar. I would still like to hear a bit more about the problems you had with dynamically switching because I believe I need to really do that if it is possible. Do you think my ASP:RequiredFieldValidator controls (generated as part of the parent control ASP:Login) will cause me the same problem you had?

I've tried the code you sketched in 2 lines above but I get a compile error on Login1 - it complains that Login1 is not declared. This is what I've been chasing - how to "get at" my LoginButton?? I am going to paste my whole user control below in case you can help spot the issue and suggest working syntax:


[Snip] Rest of the code was cut by Imar [/Snip]

On Monday, November 06, 2006 8:44:26 PM Imar Spaanjaars said:
Hi John,

If you have to post so much code, please do this on a public forum like the one at http://p2p.wrox.com and send me a link. My site just isn't the best platform for exchanging code.

That said, you get the error because you don't hav a true Logon control. What you have is a LoginView control with inside the anonymous template the ripped apart code from the Login control.

If I were you, I'd start from the beginning:

1. Create a UC and add a single Login control. You'll see that my code then works.

2. Add the entire Login control to the anonymous template of a LoginView. Use FindControl again on the LoginView to find the Login control. Once you have the Login, use FindControl again as I demonstrated earlier to find the button inside the Login control which in turn is inside the LoginView control.

From there, customize both controls so they look the way you want them to.

With your code and description, you don't need the *client side* runtime behavior I described. Setting the right buttons in code behind in the ASPX page should work.

Imar
On Monday, November 06, 2006 10:24:32 PM John Adams said:
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.
On Tuesday, November 07, 2006 7:27:15 AM Imar Spaanjaars said:
Hi John ,

Well, have you tried it out? Are things working as expected now?

The DefaultButton *does* use JavaScript to detect the button. Take a look at the HTML souce to see what I mean.

Imar
On Tuesday, November 07, 2006 7:00:42 PM John Adams said:
Hi Imar,

Yes, I've tried it and it works (as I posted on Monday). Thank you for all your help. I've learned alot and I appreciate all your time. However, please kindly read the rest of my Monday post carefully. I have the same challenge as you present in your Introduction of this QuickDocID. That is, I have one textbox with a "FIND" button and I have the username/password textboxes with a "LOGIN" button.

Like you state in your Intro, I'm looking for a way to fire the appropriate button based on what box received the data entry before the user hits the ENTER key.

So I'm not quite sure now if there is a solution to this problem. Your UPDATE at the top suggests it breaks with "validators" present. That is why I have been asking you for more info on that aspect of the problem.
On Tuesday, November 07, 2006 8:24:24 PM Imar Spaanjaars said:
Hi John,

I re-enabled the behavior on my site (thanks to source control) so you can see for yourself.

1. Go to http://imar.spaanjaars.com

2. Type in Dreamweaver in the search box and hit enter. You'll see the search page appear.

3. Next, enter the number 379 in the QuickDocId box and hit enter. You'll see this page appear again.

So far, so good. Simply by clicking the right box, the DefaultButton is dynamically switched.

Now try this:

4. Enter Dreamweaver in the *QuickDocId* box and hit enter. Nothing happens.

5. Next, click the Go button after the QuickDocId box. You'll get a message that Dreamweaver is not a valid quick doc ID.

So, this means that with the script from this article, the validators seem to break. I haven't yet found an answer for this problem, although I tried various flavors of JavaScript.

I think the problem lies in the fact that my script takes over the onkeypress of the text box. Somehow, that's causing the validators to stop working.

There may be solutions for this, or a work around, but I haven't had the time to really look into this.

Cheers,

Imar
On Tuesday, November 07, 2006 9:59:52 PM John Adams said:
Hi Imar,

I just tried the steps above at the URL you provided in step 1.
Step 2 worked as you said (search results for "Dreamweaver" displayed).

For step 3, I entered 379 (and various other numbers) and each time I hit enter after typing the number I got the Search box displayed. Strange??

Steps 4 and 5 behaved exactly as you described.

So step 3 behavior is not as expected at this URL:
http://imar.spaanjaars.com

Have I missed something again?
On Tuesday, November 07, 2006 10:07:54 PM Imar Spaanjaars said:
See, switching the default button at run-time acts weird... ;-)

I think it's a browser issue. What browser are you using? It works for me on IE 6 and 7, but not in FireFox.

Imar
On Tuesday, November 07, 2006 10:33:31 PM John Adams said:
Oh yes....I am using Firefox when browsing your site! I'll experiment more tomorrow with IE 6. Thanks.
On Thursday, November 09, 2006 4:38:00 PM John Adams said:
Hi Imar,

You are correct again - your code works beautifully in IE6, with this slight misbehavior in Firefox 1.5. To sum up a bit, here is my current server-side code to establish the default button in one of my user-controls called loginMechanism.ascx:

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

Since I have another user control, I think I will try adding the onclick attribute to the corresponding textbox as you show here to improve BOTH user controls behavior (with IE). Assuming I use a similar technique to find my txtPassword control inside my LoginView control, I would then be able to do something like:

myFoundTextBox.Attributes.Add("onclick",
   "document.forms[0].onkeypress = "
   + "new Function(\"return WebForm_FireDefaultButton(event, '"
   + myButton.UniqueID + "');\");");  

Granted, I will have to change C# syntax to VB and the other syntax looks strange to me (looks like something like escape characters). I will study up on this and FireDefaultButton.

I want to sincerely thank you for patiently sticking with me during my questions about this. I've learned very much already and your site alone is filled with many other good things I'd like to study. My very best regards to you,
John
On Thursday, November 09, 2006 7:46:45 PM Imar Spaanjaars said:
Hi John,

My pleasure....

The weird stuff is indeed escaping of the " character. In VB.NET you can accomplish the same with doubling the " character, and dropping the semi colon:

myFoundTextBox.Attributes.Add("onclick",
   "document.forms[0].onkeypress = "
   + "new Function(""return WebForm_FireDefaultButton(event, '"
   + myButton.UniqueID + "');"");")

Make sure it's all on one line, or use the line continuation character (_) to spread the code over multiple lines.

Cheers,

Imar
On Sunday, November 19, 2006 5:29:09 AM Garfield Lindo said:
Nevermind I found the answer right here at your site, thank you so much for publishing this information.
On Tuesday, November 28, 2006 6:23:46 AM Thomas said:
Hi Imar,

I am facing a strange issue. I am using DefaultButton inside Panel control and it is assinged as DefaultButton="btnAddToCart". This DefaultButton functionality works like charm on my development PC (winxp sp 2 and it works with ie7 & firefox) also this page is referencing Master page. But when I moved this website into production (live) this doesn’t work which is basically on a hosting company server.

Do think is there any thing specially on server enviourment it is causing the issue and is there any thing which I can tell the hosting company to enable to get start work this DefaultButton?

Even I put the setup another winxp sp2 pc and it worked as well. i think something causing from the server enviourment or the security settings of the hosting server.

What you think about this behavious?

thanks
thomas
On Tuesday, November 28, 2006 3:02:43 PM Imar Spaanjaars said:
Hi Thomas,

I have no idea; never seen this before. Is there a live URL that I can look at?

Imar
On Monday, January 08, 2007 6:03:39 PM Bern Stangroom said:
Hi,
Apologies in advance for my ignorance of all things .net as I'm just starting out...  I'm using a defaultbutton on my asp.net 2 form which is working fine, except that multiple key presses get stored up whilst the page is being processed as the server-side (and results in multiple posts).  I've had this problem with the user clicking the button which I've resolved by disabling the control with javascript after it is clicked, but this doesn't prevent the default button action (i.e. the enter key) from working.  I was hoping to use your approach above as a possible solution i.e. dynamically changing the default button to a dummy button when the default button were first activated (i.e. subsequent enters would cause the dummy button to activate), but I'm having problems getting this to work and I'm not sure that I've fully grasped the concepts.  Any suggestions?

Thanks,
Bern.
On Monday, January 08, 2007 6:56:02 PM Imar Spaanjaars said:
Hi Bern,

In addition to disabling the button, you can also write a handler for the form's onsubmit event. Inside that event, keep track of a counter and then either allow the submit (when the counter is 1) or return false when the counter is greater than 1.

That way, the form won't be submitted when the page tries to post back the second time.

Does this help?

Imar
On Tuesday, January 09, 2007 3:51:41 PM Bern Stangroom said:
Yes it does!  Thanks very much and sorry that it didn't really end up relating to this subject.
On Tuesday, January 09, 2007 6:05:02 PM Imar Spaanjaars said:
Hi Bern,

You're welcome....

Imar
On Saturday, January 13, 2007 11:46:18 AM natraj said:
i read your document (QuickDocId-379).it is very nice and i appreciate u a lot.
On Tuesday, September 04, 2007 1:51:38 PM Ba Dang said:
hi, thanks for the article.

If placing a panel outside your login control doesn't work, try wrapping the panel inside the asp:login control and reference it through there.


------------------------------------------
[asp:Login id="login" runat="server"]
[asp:panel defaultbutton="targetbutton"]

***username textbox here***
***password textbox here***

[asp:button id="targetbutton" runat="server"] Submit [/asp:button]

[/asp:panel]
[/asp:Login]
On Wednesday, January 02, 2008 1:22:02 PM Daniel said:
I am dynamically adding TextBox controls to an UpdatePanel, and this seems to be a great way to solve the DefaultButton issue for me because I am recreating the controls during each async postback, so I can't simply set the Form's DefaultButton as the UniqueID of the TextBox because that TextBox won't survive a round trip.

However, it seems in my scenario, only the default DefaultButton that I declare in markup fires when Enter is pressed. In IE7, nothing happens, in Firefox, I receive an error when the anonymous function is raised: 'event is not defined'---Has there been a recent change that might change the necessary syntax to add the onclick event?
On Tuesday, March 10, 2009 7:40:14 AM Siju said:
Thanks a lot. it worked for me. Actually I used image as button before, but after changing to Imagebutton it worked. Thanks once more

Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the QuickDocId of the document.

For more information about the Talk Back feature, check out this news item.