Using Panel.DefaultButton property with LinkButton control in ASP.NET

Aug 25
2007 12:53 (ASP.NET, Development) · Русский (23,817 views)

ASP.NET has great limitation — only one server form on the page. Even if you are developing complex page, which looks like several forms with different submit buttons, in fact you have only one form. So we have a problem: How browser understanding which button should be triggered when user pressed ENTER? It uses first Button control (usually that’s wrong), and if you have LinkButton’s, they would never be triggered. In ASP.NET 2.0 new property has been added to the Panel and HtmlForm controls — DefaultButton, which can be used to specify ID of the control, which implements IButtonControl interface (usually Button and LinkButton). This button control would be triggered when user pressed ENTER. But there is one big problem exist: LinkButton control would not be triggered in Firefox on ENTER. In this article I will show why this problem take place and how to solve it.

Let’s look how DefaultButton is working in ASP.NET. Here is simple example:

<asp:Label runat="server" ID="lblHello" />
<asp:Panel runat="server">
    First name: <asp:TextBox runat="server" ID="txtFirstName" />
    <asp:LinkButton ID="lbHello" runat="server" Text="Click me" OnClick="lbHello_Click" />
</asp:Panel>
protected void lbHello_Click(object sender, EventArgs e)
{
    lblHello.Text = String.Format("Hello, {0}", txtFirstName.Text);
}

When you will try to press ENTER button inside the text box, form will be submitted to the server, but LinkButton’s Click event will not be fired. Let’s try to specify DefaultButton property of the panel:

<asp:Panel runat="server" DefaultButton="lbHello">
    First name: <asp:TextBox runat="server" ID="txtFirstName" />
    <asp:LinkButton ID="lbHello" runat="server" Text="Click me" OnClick="lbHello_Click" />
</asp:Panel>

Great! It’s working perfectly in Internet Explorer, but what about Firefox? Oops, we found a problem. You could find solution at the end of the post, but first I want to show why this problem occurs. When you specify DefaultButton property, ASP.NET generates following code:

<div onkeypress="javascript:return WebForm_FireDefaultButton(event, 'lbHello')">
</div>

Here is WebForm_FireDefaultButton method, defined in ASP.NET JavaScript library:

function WebForm_FireDefaultButton(event, target) {
    if (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") {
            defaultButton.click();
            event.cancelBubble = true;
            if (event.stopPropagation) event.stopPropagation();
            return false;
        }
    }
    return true;
}

The problem occurs in the code typeof(defaultButton.click) != “undefined” — Firefox does not define click() method for the a element, so the form will be submitted without __EVENTTARGET parameter, and button will not be triggered. The simplest way to solve the problem is to define click() method for the a:

var b = document.getElementById('<%= lbHello.ClientID %>');
if (b && typeof(b.click) == 'undefined') {
    b.click = function() { 
        var result = true;
        if (b.onclick) result = b.onclick();
        if (typeof(result) == 'undefined' || result) {
            eval(b.getAttribute('href'));
        }
    }
}

Our click() method imitates a element behavior: first it calls onclick() method (OnClientClick attribute of the LinkButton), and if it returns false — stops processing. Then it evals href attribute (where ASP.NET puts __doPostBack call).

Let’s create custom control which encapsulates this logic:

using System;
using System.Web.UI.WebControls;

namespace App_Code
{
    public class LinkButtonDefault : LinkButton
    {
        protected override void OnLoad(System.EventArgs e)
        {
            Page.ClientScript.RegisterStartupScript(GetType(), "addClickFunctionScript",
                _addClickFunctionScript, true);

            string script = String.Format(_addClickScript, ClientID);
            Page.ClientScript.RegisterStartupScript(GetType(), "click_" + ClientID,
                script, true);
            base.OnLoad(e);
        }

        private const string _addClickScript = "addClickFunction('{0}');";

        private const string _addClickFunctionScript =
            @"  function addClickFunction(id) {{
            var b = document.getElementById(id);
            if (b && typeof(b.click) == 'undefined') b.click = function() {{
                var result = true; if (b.onclick) result = b.onclick();
                if (typeof(result) == 'undefined' || result) {{ eval(b.getAttribute('href')); }}
            }}}};"
;
    }
}

And corresponding .aspx file:

<%@ Register Namespace="App_Code" TagPrefix="ac" %>
<asp:Label runat="server" ID="lblHello" />
<asp:Panel runat="server" DefaultButton="lbHello">
    First name: <asp:TextBox runat="server" ID="txtFirstName" />
    <ac:LinkButtonDefault ID="lbHello" runat="server" Text="Click me" OnClick="lbHello_Click" />
</asp:Panel>

Of course, JavaScript code should be moved out from the C# code, but for my example it’s good enough. If you are using ASP.NET AJAX library, you should use ScriptManager.RegisterStartupScript method instead of ClientScriptManager.RegisterStartupScript.

Hope, this post will help you. Your comments are welcome.

22 Responses to 'Using Panel.DefaultButton property with LinkButton control in ASP.NET'

Subscribe to comments with RSS or TrackBack to 'Using Panel.DefaultButton property with LinkButton control in ASP.NET'.

1
parthiban
said on 2007-09-06 at 1.42 pm

asp.net panel scroll bars not visible in opera.why?

2
said on 2007-09-19 at 4.25 pm

hi
I am using Aspnet ajax in my application, i used asp button for submiting a form, beacuse asp:Button work in both condition when Javascript is enable or disabled.
but asp:button are not look good in mac broswer so client do want asp:Button/asp:ImageButton in whole application.
Please advise What would be the replcaement of asp:Button/asp:ImageButton which will work in both condition when Javascript is enable or disabled.

Thanks

Regards
Raghvendra
to_raghvendra@yahoo.com

3
said on 2007-09-19 at 4.47 pm

asp:LinkButton works only when JavaScript is enabled, you right. I see only one solution: add two buttons at the same time (for browsers that does not support JavaScript — asp:Button, visible by default, and asp:LinkButton for ones, that support JavaScript), and switch their visibility using JavaScript. Something like this:

<asp:Button runat="server" ID="btnSubmit" Text="submit" />
<asp:LinkButton runat="server" ID="lbSubmit" style="display:none" Text="submit" />
<script type="text/javascript">
    document.getElementById("<%= btnSubmit.ClientID %>").style.display = 'none';
    document.getElementById("<%= lbSubmit.ClientID %>").style.display = '';
</script>

But of course this is not perfect solution. BTW, you could use images as background of the asp:Button or asp:ImageButton, and they would look perfectly in Safari.

4
Tyler Thompson
said on 2007-09-27 at 7.52 pm

That worked perfectly! Thank you for your post.

5
said on 2007-10-25 at 8.45 pm

[...] is one solution that creates their own “click” event for the LinkButton. You can look at it here (this solution does work as well, i just found it too much). I wanted something simpler, Simple is [...]

6
said on 2007-11-14 at 7.39 am

[...] But of course if you are using a LinkButton, then its a whole another ball game. None of the techniques described above might work for you. But you are in luck, this page has what you need to get around that — http://kpumuk.info/asp-net/using-panel... [...]

7
said on 2007-12-12 at 11.27 pm

One simple way to get around the Linkbutton issue and the firefox issue is to set up a “shadow” button on the page with a style="display:none;"

So, say I have a login form, I will put a link button on the form in case the user is going to click it directly. Then, just underneath it I will add a hidden asp:Button, with display:none, and tie that to the same event as the regular login linkbutton.

Works in both IE7 and FF2 as far as I can tell, and doesn’t require any javascript — just a stupid workaround.

8
Тимур
said on 2008-02-15 at 8.53 am

Работает идеально, спасибо! Но… Очень бы хотелось, чтобы работало в опере по Ctrl + Enter (автозаполнение). Есть идеи?
Спасибо.

9
Chris
said on 2008-02-23 at 5.49 am

Dave’s solution is the way to go.

10
uttam
said on 2008-03-10 at 3.43 pm

Hi guys i found solution finally.

Setting link button as Default button for FIREFOX as well as IE:
use this fallowing code–>

in .aspx file—————————

function clickButton(e,buttonid) {
    debugger;
    var bt = document.getElementById(buttonid);
    if (typeof(bt) == 'object') {
        if (navigator.appName.indexOf("Netscape") > -1) {
            if(e.keyCode == 13) {
                if (bt && typeof(bt.click) == 'undefined') {
                    bt.click =  addClickFunction1(bt);
                }
            }
        }
        if (navigator.appName.indexOf("Microsoft Internet Explorer") > -1) {
            if (event.keyCode == 13) {
                bt.click();
                return false;
            }
        }
    }
}

function addClickFunction1(bt) {
    debugger;
    var result = true;
    if (bt.onclick) result = bt.onclick();
    if (typeof(result) == 'undefined' || result) {
        eval(bt.href);
    }
}

————————-

in aspx.cs file (write code for the text boxes u required)

aspx.cs file(C#.net code)—>
in Page_Load Event

txtUserName.Attributes.Add("onkeypress", "javascript:return clickButton(event,'" + btnSearch.ClientID + "');");
11
uttam
said on 2008-03-10 at 3.50 pm

reg Above Code–>
Please read this for the reference of the above code , and read the ID’s for the textbox’s and Link Buttons

for the above code in aspx form ,we have
a
asp Text box with id “txtUserName”
and
a
link button with id “btnSearch”

like

12
Jared Holgate
said on 2008-04-21 at 1.16 pm

This solution worked perfectly. Thank you very much.

13
Martin
said on 2008-04-22 at 2.38 pm

Solution is ok. Unfortunatelly, this does not work under Firefox 3.

Anyone know how to do it?

14
Ramana
said on 2008-05-22 at 5.59 am

Hi uttam,

i am implemented what you are given the code in my aspx page, but in FireFox again its not working, when i enter key in textbox the cursor goes to next button, could you please give me any idea.

Thanks
Ramana

15
Simon
said on 2008-06-09 at 11.42 am

Hi,

I have implemented this fix and it seems to be ok in most cases. However, if I have a form with asp.net validators then it only works once. e.g. Enter an invalid entry, press enter and the correct button is clicked. However, press enter again, and the wrong one is clicked!

Anyone have any ideas? Thanks in advance.

Simon.

16
mdespesse
said on 2008-06-16 at 12.45 pm

It seems that firefox 3 automatically htmlencode hrefs. So our :

javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOption[...]

becomes :

javascript:WebForm_DoPostBackWithOptions(new%20WebForm_PostBackOption[...]

which obviously doesn’t work as expected.
To have it work again, change the end of addClickFunctionScript to :

eval(unescape(b.href));
17
mdespesse
said on 2008-06-16 at 1.25 pm

After some research, it seems that DOM specs stand that href attribute should be an URI and that to get the exact content of href, one should use :

eval(b.getAttribute('href'))
18
said on 2008-06-16 at 3.48 pm

Nice point, mdespesse! Thanks for sharing your experience.

19
Jared Holgate
said on 2008-06-18 at 10.14 am

Mdespesse’s point in 17 makes this solution work perfectly in FF3. Thanks.

20
said on 2008-08-21 at 12.42 am

Based on Dave’s solution (post #7).

<asp:Panel ID="pnNewstatus" runat="server" DefaultButton="btnHiddenSubmit">
New Status:
<asp:TextBox ID="txbNewStatus" runat="server"/>
<asp:LinkButton ID="lnkBtnNewStatusCancel" runat="server" Text="Cancel" />
<asp:LinkButton ID="lnkBtnNewStatusSubmit" runat="server" Text="Submit" />
<asp:Button ID="btnHiddenSubmit" runat="server" />
</asp:Panel>

and then, on the code behind:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  btnHiddenSubmit.Attributes.Add("style", "display:none;")
End Sub

Protected Sub lnkBtnNewStatusSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lnkBtnNewStatusSubmit.Click, btnHiddenSubmit.Click
'Do What you need to do for those clicks
End Sub
21
Marlon Bohol
said on 2008-08-21 at 4.32 am

This is what i did in ASP.NET code behind and it works pretty well in both IE and FF:

Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
        JavaScriptLoad()

    Private Sub JavaScriptLoad()

        Dim addClickFunctionScript As StringBuilder = New StringBuilder()

        addClickFunctionScript.Append("  function addClickFunction(id) {{ ")
        addClickFunctionScript.Append(" var b = document.getElementById(id); ")
        addClickFunctionScript.Append(" if (b && typeof(b.click) == 'undefined') b.click = function() {{ ")
        addClickFunctionScript.Append(" var result = true; if (b.onclick) result = b.onclick(); ")
        addClickFunctionScript.Append(" if (typeof(result) == 'undefined' || result) {{ eval(b.getAttribute('href')); }} ")
        addClickFunctionScript.Append(" }}}}; ")

        Dim addClickScript As String = "addClickFunction('{0}');"
        Dim ClickScript As String = String.Format(addClickScript, lnkLogin.ClientID)

        Page.ClientScript.RegisterStartupScript(Me.GetType(), "addClickFunctionScript", addClickFunctionScript.ToString(), True)
        Page.ClientScript.RegisterStartupScript(Me.GetType(), "click_" + lnkLogin.ClientID, ClickScript, True)

    End Sub

corresponding .aspx file

<asp:Panel runat="server" DefaultButton="lbHello">
    First name: <asp:TextBox runat="server" ID="txtFirstName" />
    <asc:LinkButton ID="lbHello" runat="server" Text="Click me"  />
</asp:Panel>
22
Jake H
said on 2008-09-11 at 6.17 pm

The simplest, cross-browser approach I’ve seen is at this guy’s site:

http://weblogs.asp.net/jeff/archive/2005/07/26/420618.aspx

Just one line and you’re all set…
MyPasswordTextBox.Attributes.Add(”onKeyPress”, “javascript:if (event.keyCode == 13) __doPostBack(’” + MySubmitButton.UniqueID + “‘,”)”)

Post a comment

You can use simple HTML-formatting tags (like <a>, <ul> and others). To format your code sample use <code lang="php">$a = "hello";</code> (allowed languages are ruby, php, yaml, html, csharp, javascript). Also you could use <code>$a = "hello";</code> and its syntax would not be highlighted. If you are not using <code> tag, replace < sign with &lt;.

Submit Comment

 
Copyright © 2005 - 2008, Dmytro Shteflyuk