The Problem: I don't like using the ASP:Button control on the ASP.Net Applications that I build. Mainly because I have little control over how they appear and act. The ASP:ImageButton is better, but it requires that I (or someone) make images with the text required - and when going international that work snowballs quickly.
The ASP:LinkButton is my control of choice. I can use CSS to make rollover and hover states, use what ever text I'd like. Out of the box, as long as IE is the browser everything works - but as soon as you try to submit a form with a LinkButton as the default button in FireFox, the form just reloads and any values that were input are lost.
The Investigation: I found several posts and examples, but most of them were for extending the ASP:Button or ASP:ImageButton controls. I also noticed that they were trying to submit the form via a PostBack method and with the LinkButton it just wasn't working.
The Solution The answer was right there in the page's source as sent to the browser. The LinkButton control gets rendered as a link [A] to the browser. All you need to do to cause the button to fire is go to the address in the HREF.
The Code: Add this code to a SCRIPT block in your MasterPage (or better yet, to a seperate .JS page that is linked to your MasterPage).
function DefaultButtonKeyPress(evt, thisElementName) {
if(evt.which || evt.keyCode)
{
if ((evt.which == 13) || (evt.keyCode == 13))
{
// alert('post back href: ' +
document.getElementById(thisElementName).href);
location =
document.getElementById(thisElementName).href;
return false;
}
}
else
{
return true;
}
}
All that code does is send the browser to the location that you'd go to if you clicked the link, but only if you hit the ENTER button when in a TextBox that calls the JavaScript method.
To get your TextBoxes to call that method, you need to add the following method to your project somewhere. (I have a PresentationLayerTools.vb class where I put all this code, you might like it somewhere else).
Public Overloads Shared Sub DefaultButton(ByRef TextBox As System.Web.UI.WebControls.TextBox, ByRef LinkButton As
System.Web.UI.WebControls.LinkButton)
TextBox.Attributes.Add("onkeydown", "DefaultButtonKeyPress(event, '"
& LinkButton.ClientID & "')")
End Sub
All that code does is add a OnKeyDown event handler to fire the JavaScript method above to the specified ASP:TextBox. The method listens for KeyDown events, if if finds one, it checks to see if the Key you pressed was the ENTER - if it is then it send the browser to the location of the ASP:LinkButton's HREF attribute (which, buy default is a call t another ASP.Net controlled JavaScript method that fires off a PostBack; I'm not sure what all else it does, but it works so I'm happy).
Finally, you need to add the following to the code behind for your pages to tell ASP.Net to execute the DefaultButton method above. I suggest doing it during the page's PreRender event; but it could go other places too.
Protected Sub Page_PreRender(ByVal sender As Object, ByVal e
As System.EventArgs) Handles MyBase.PreRender
Page.Form.DefaultButton = LinkButtonLogOn.UniqueID
PresentationLayer.Tools.DefaultButton(Me,
TextBoxEmail, LinkButtonLogOn)
PresentationLayer.Tools.DefaultButton(Me,
TextBoxPassword, LinkButtonLogOn)
End Sub
Please note that you have to add a call to the DefaultButton method for each TextBox you have on your form that you want to submit the form on.
The Conclusion: I hope that makes sense and works for you, it took me a half a day of banging my head as I searched the Web for a fix. This morning after a nice nights rest the answer was obvious; but because I couldn't find any other similar suggestions I figured I ought to post this to help someone else out.
This code has been tested with: IE 7 and 6 on Windows Server 2003 and Windows XP, FireFox 2 on Windows Server 2003, FireFox 2 on OS X 10.4.10, and Safari 2 on OS x 10.4.10. If you try it on other platforms please let me know how it works!
2 comments ↓
I came across this posting while researching a similar issue, though my issue had to do specifically with safari on Windows XP. I’d like to share the method I used, as it differs slightly from your approach.
Rather than opting to register onkeypress events on each and every form field via the codebehind, I created my own javascript object to unobtrusivly add the event listeners to container objects (which can be any html object encasing form fields) using the appropriate eventHandler registration method.
In the example below, the container element is actually a table.
First, the code:
//create custom defaultButtons object
var defaultButtons={
registerButton:function(cId,bId){
var oC=document.getElementById(cId);
var oB=document.getElementById(bId);
if(typeof(oC)!=='undefined'&&typeof(oB)!=='undefined'){
if(typeof(oC.addEventListener)!=='undefined'){
oC.addEventListener('keypress',function(e){
defaultButtons.fireDefaultButton(e,oB);
},false);
}else if(typeof(oC.attachEvent)!=='undefined'){
oC.attachEvent('onkeypress',function(e){
defaultButtons.fireDefaultButton(e,oB);
});
}
}
},
fireDefaultButton:function(e,lbtn){
if(!e.which&&!e.keyCode){
return;
}else{
var k=(e.which||e.keyCode);
try{
if(k===13){
lbtn.focus();
eval(lbtn.href);
return true;
}
}
catch(err){
return false;
}
}
}
};
//define which containers are associated with which buttons
defaultButtons.registerButton('sign-in','');
defaultButtons.registerButton('go-home','');
Now, the two html tables on the same page (but with different ids and different default buttons)
<label for="">User ID:
<label for="">Password:
Sign In
This is another table
Go Home
I’ve tested this in Firefox, IE7, Opera 9, Safari (Windows XP) & Mozilla. Sadly, I have no way to test it’s functionality in IE6, nor IE / Safari on the Mac.
In addition, there may be a cleaner way of doing this, though admittedly I haven’t gone much further. I am by no means a javascript expert…so if you spot anything, please let me know.
One caveat…you’ll notice I used the dreaded “eval” method to execute the __doPostback function in the link button’s href property. The reason for that is due to the issue I was having in Safari on Windows XP. For some reason, Safari knows that lbtn.href is a string, and has a length of 66…but it does not execute that function when setting location.href=lbtn.href…hence the call to eval();
I’m sure there’s a way of doing this without calling eval…but I’m stumped as to what it could be.
Anyway, just thought I’d share. Hope you don’t mind.
Whoops…
define which containers are associated with which buttons should actually be:
defaultButtons.registerButton('sign-in','<%=lbtnSignIn.ClientID%>');
defaultButtons.registerButton('go-home','<%=lbtnGoHome.ClientID%>');
Also, I actually posted raw html code for the tables and forms like an idiot…so rather than go through converting those tables…I’ll simplify below.
Basically, each container (in my case, tables) get’s an id, which are the “sign-in” and “go-home” strings in the code statements above. These tables then contain various form elements, checkboxes, radiobuttons, textboxes, select boxes, etc. Then, when the “enter” key is pressed while inside aforementioned container, the keypress event is fired, and the default button associated with that container is executed.
One exception I just realized is that I didn’t allow for textareas in my js object…so once the keypress event is fired, you would have to check the target or srcElement type to make sure it’s not a typeof ‘textarea’ before executing the call to the defaultbutton’s href property (if that makes any sense).
You must log in to post a comment.