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

Posted by Dmytro Shteflyuk on under ASP.NET · Русский (111,501 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:

1
2
3
4
5
<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>
1
2
3
4
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:

1
2
3
4
<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:

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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:

1
2
3
4
5
6
7
8
9
10
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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:

1
2
3
4
5
6
<%@ 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.

23 Responses to this entry

Subscribe to comments with RSS

parthiban
said on September 6, 2007 at 1:42 pm · Permalink

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

said on September 19, 2007 at 4:25 pm · Permalink

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

said on September 19, 2007 at 4:47 pm · Permalink

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:

1
2
3
4
5
6
<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.

Tyler Thompson
said on September 27, 2007 at 7:52 pm · Permalink

That worked perfectly! Thank you for your post.

Dave @
said on December 12, 2007 at 11:27 pm · Permalink

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.

Тимур
said on February 15, 2008 at 8:53 am · Permalink

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

Chris
said on February 23, 2008 at 5:49 am · Permalink

Dave’s solution is the way to go.

uttam
said on March 10, 2008 at 3:43 pm · Permalink

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—————————

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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

1
txtUserName.Attributes.Add("onkeypress", "javascript:return clickButton(event,'" + btnSearch.ClientID + "');");
uttam
said on March 10, 2008 at 3:50 pm · Permalink

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

Jared Holgate
said on April 21, 2008 at 1:16 pm · Permalink

This solution worked perfectly. Thank you very much.

Martin @
said on April 22, 2008 at 2:38 pm · Permalink

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

Anyone know how to do it?

Ramana
said on May 22, 2008 at 5:59 am · Permalink

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

Simon @
said on June 9, 2008 at 11:42 am · Permalink

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.

mdespesse
said on June 16, 2008 at 12:45 pm · Permalink

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

1
javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOption[...]

becomes :

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

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

1
eval(unescape(b.href));
mdespesse
said on June 16, 2008 at 1:25 pm · Permalink

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 :

1
eval(b.getAttribute('href'))
Jared Holgate
said on June 18, 2008 at 10:14 am · Permalink

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

said on August 21, 2008 at 12:42 am · Permalink

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

1
2
3
4
5
6
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:

1
2
3
4
5
6
7
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
Marlon Bohol
said on August 21, 2008 at 4:32 am · Permalink

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    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

1
2
3
4
<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>
Jake H @
said on September 11, 2008 at 6:17 pm · Permalink

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 + “‘,”)”)

Joe @
said on October 8, 2008 at 4:57 am · Permalink

I have a question: I try to find out the value of the disabled property of linkbutton in javascript. It’s not a problem in IE but it’s undefined in Firefox. My problem is that although the link is disabled clicking it triggers onClientClick event which shows a message. I want to check if the link is disabled before showing the message however the disabled property is undefined in FireFox. Thank you in a advance for your help.

Comments are closed

Comments for this entry are closed for a while. If you have anything to say – use a contact form. Thank you for your patience.