ASP .NET - Submit on Enter - Prevent 'defaultbutton' when other button has focus - asp.net

I have a search form consisting of the following...
<asp:Panel DefaultButton="btnSearch" ... >
[...search criteria fields...]
<asp:Button ID="btnReset" OnClick="btnReset_Click" ... />
<asp:Button ID="btnSearch" OnClick="btnSearch_Click" ... />
</asp:Panel>
The desired behaviour is that pressing the Enter key should invoke btnSearch_Click (which is working thanks to the DefaultButton attribute in the asp:panel)
The problem is that when btnReset has focus, pressing Enter should invoke btnReset_Click instead (which it doesn't - it's always btnSearch).
Is this easily achievable somehow, or am I going to have to hack up some bespoke JS to intercept .NET's defaultButton event handler?
Thanks in advance.
ETA: Here's a reusable solution I went with based on HenryChuang's accepted answer below.
Add a custom attribute preventDefaultButton to panels.
<asp:Panel DefaultButton="btnSearch" preventDefaultButton="btnReset" >
[...search criteria fields...]
<asp:Button ID="btnReset" OnClick="btnReset_Click" ... />
<asp:Button ID="btnSearch" OnClick="btnSearch_Click" ... />
</asp:Panel>
Run the following jQuery on pageload.
$("div[preventDefaultButton]").each(function () {
var div = $(this);
var keypressEvent = div.attr("onkeypress");
var btn = $("input[id$=" + div.attr("preventDefaultButton") + "]");
btn.on("focus", { div: div }, function (event) {
event.data.div.attr("onkeypress", "");
});
btn.on("blur", { div: div, keypressEvent: keypressEvent }, function (event) {
event.data.div.attr("onkeypress", event.data.keypressEvent);
});
});

see the panel generate html
<div id="yourPanelClientID" onkeypress="javascript:return WebForm_FireDefaultButton(event, 'btnSearch')">
so, when btnReset onfocus we break onkeypress event of Panel, add below to btnReset,
remember when btnReset onblur, change Panel keypress to oringinal
onfocus="document.getElementById('yourPanelClientID').onkeypress = '';"
onblur="funA();"
function funA() {
document.getElementById('yourPanelClientID').onkeypress = function () { return WebForm_FireDefaultButton(event, "btnSearch") };
}
like this
<asp:Button ID="btnReset"
onfocus="document.getElementById('yourPanelClientID').onkeypress = '';"
onblur="funA();"
onclick="btnReset_Click" .../>

you need to change DefaultButton attribute of your panel but this will work for only one at a time, better way would be to have Javascript to capture enter event and process accordingly.
One way can be having multiple panels, have a look at http://www.jstawski.com/archive/2008/09/23/multiple-default-buttons.aspx

Related

ASP.NET DataPager Next/Previous buttons client onlick event

How can I add client (javascript) onclick event to Next/Previous links in DataPager?
You Can add a new button in data pager and worked on it's click event.
<asp:ListView runat="server" ID="ListView1"
DataSourceID="SqlDataSource1">
<LayoutTemplate>
<table runat="server" id=" table1">
<tr runat="server" id="itemPlaceholder">
</tr>
</table>
<!-- This is the pager. Define all necessary markup here. -->
<asp:DataPager runat="server" ID="DataPager" PageSize="5">
<Fields>
<asp:TemplatePagerField>
<PagerTemplate>
<asp:Button ID="btn_Submit" runat="server" Text="Button" onclientclick="eventHandler(this)" />
</PagerTemplate>
</asp:TemplatePagerField>
</Fields>
</asp:DataPager>
</LayoutTemplate>
</asp:ListView>
The answer above (by Sheery) works great for custom pager elements. However, when using the stock Numeric or Next/Previous pager styles of the ListView or DataGrid, you don't have near as much control. By using client-side jQuery/javascript selectors, you can unobtrusively attach client-side handlers to the pager elements. For this example, I'm tracking if any form field value has changed and if so, then prior to allowing the pager to execute it's default behavior of posting back to the server, we're confirming with the user that they have unsaved changes.
$(function () {
var _formChanged = false;
// grabs all pager links in last row of table named dgQuestions
// and attachs a click eventhandler via jQuery library
$("#dgQuestions tr:last a").click(function(e) {
if (!_formChanged)
return true;
var ok = confirm('You have UNSAVED changes. Continue?');
if (ok) {
return true;
}
else {
//Prevent the submit event and remain on the screen
e.preventDefault();
return false;
}
});
// delegates change event handling to the form to indicate if ANY
// form field value changed for testing prior to paging
$("#form1").change(function(e) {
_formChanged = true;
});
});
});
OR
Can also utilize the beforeunload event of the window to catch ANY navigate-away action to test for unsaved changes as well. This code excludes the actual click of the 'save' button.
$(window).on('beforeunload', function (e) {
if (e.originalEvent.explicitOriginalTarget.id != "btnSave") {
if (_formChanged)
return 'You have UNSAVED changes. Continue?';
}

How to correct ASP.NET webform jquery reference being lost on partial postback

Within an asp.net webform I have some jquery that controls the positioning of elements on the page. Since this is a webform and some of these controls talk to the server to get jquery to work I have the controls nested in an AJAX UpdatePanel to prevent postbacks from resetting my controls.
aspx:
<asp:UpdatePanel ID="searchupdatePanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<div id="searchholder" >
<div id="searchoptions">
Close Advanced Search
<br />
Filters
</div>
<div id="search" class="searchcontainer">
<asp:TextBox ID="tbsearchterm" CssClass="watermark" runat="server" OnTextChanged="tbsearchterm_TextChanged" />
<div class="buttons">
<asp:LinkButton runat="server" Text="Search" class="button search-big" ID="btnSearch" OnClick="btnSearch_Click" />
<asp:LinkButton runat="server" Text="Fx" class="button left big" ID="btnOperators" />
<asp:LinkButton runat="server" Text="Save" class="button right big" ID="btnSave" />
</div>
</div>
<div id="divAdvSearch">
</div>
</div>
</ContentTemplate>
</asp:UpdatePanel>
<div id="divBody">
<asp:UpdatePanel runat="server" UpdateMode="Always">
<ContentTemplate>
<div id="divSearchResults" visible="true" runat="server">
<uc:SearchResultsControl ID="SearchResultsControl" runat="server"></uc:SearchResultsControl>
</div>
</ContentTemplate>
</asp:UpdatePanel>
When the search button is clicked I modify the css class for the search control to reposition my search div layer which is the update panel "searchudpatepanel"
searchcontrol.js
$(function () {
$("#searchupdatePanel").addClass("searchmenubar");
$("#btnClose").hide();
});
$(function () {
$("#btnSearch").click(function () {
$(".searchmenubar").animate({ "margin-top": "5px" }, "fast");
$("#btnAdvanceSearch").show();
$("#btnFilters").show();
$("#btnClose").hide();
$("#divAdvSearch").hide();
alert("search");
});
});
The button click also calls serverside code to retrieve and populate the results within a user control called SearchResultsControl ( second update panel)
Where I am confused is when the searchResult Control is loaded with the results all references to the jquery classes are lost. As a result every div element that is hidden or button click that is called ceases to work. Working through this in debug I can see when the user control is called the Page_Load for the default.aspx file is invoked as second time. I assume this partial load is dropping reference to the js files I just don't know how to correct this.
I tried a test within the page load using IsStartupScriptRegistered to see if the js was getting called
string csname = "PopupScript";
Type cstype = this.GetType();
ClientScriptManager cs = Page.ClientScript;
if (!cs.IsStartupScriptRegistered(cstype, csname))
{
StringBuilder cstext1 = new StringBuilder();
cstext1.Append("<script type=text/javascript> alert('Hello World!') </");
cstext1.Append("script>");
cs.RegisterStartupScript(cstype, csname, cstext1.ToString());
}
Here on the initialization of the page I would see the pop up occur however when the UserControl was loaded I would pass through this a second time in the page load but the alert never displayed( I assume this is due to a partial load so the browser thinks the script is already registered).
The only other thing I can think of is I am overriding the rendering of the UserControl being loaded as it loads a custom result set.
protected override void Render(HtmlTextWriter htw)
{
if (IsPostBack)
{
QueryResponse qr = iu.GetSearchResults(SearchTerm);
int num = qr.TotalMatchesReturned;
SearchData sd = new SearchData();
htw.Write("<table style='width: 100%; height:100%'><tr ><td style='width: 50%'>");
htw.Write("<div id='divResultDetail' runat=server >");
htw.Write("<script type='text/javascript' src='../js/paging.js'></script><div id='pageNavPosition'></div><table id='results'>");
for (int i = 0; i < num; i++)
{
...edited for brevity.
Any suggestions or guidance as to why I am losing reference to the jquery functions? I am not using master pages so I haven't used the ASP ScriptManager.
This all worked fine prior to using UpdatePanels. I define "fine" as: the postback was reloading/registering the js files each time, so they were being reset (which was okay). However, now with some other changes needed I need to look at leveraging UpdatePanels.
Thanks for any suggestions or ideas.
You can use the live or delegate jQuery methods to get your handlers to be bound to any elements added to the page.
Alternatively, if you need some setup to always happen after every partial postback in addition to original page load, you can put it in a pageLoad method instead of document.ready. ASP.NET calls this on page load, and after every partial postback.
function pageLoad()
{
// Setup code here
}
Check this article for more:
http://encosia.com/document-ready-and-pageload-are-not-the-same/
You need to use delegate for the button click. It will assure that all elements present and future will be bound to the event handler.
http://api.jquery.com/delegate/
$("body").delegate("#btnSearch", "click", function () {
$(".searchmenubar").animate({ "margin-top": "5px" }, "fast");
$("#btnAdvanceSearch").show();
$("#btnFilters").show();
$("#btnClose").hide();
$("#divAdvSearch").hide();
alert("search");
});
You need to rebind the elements when the update panel finish updating. Like this,
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function () {
$('#add').click(function () {
});
$('#addPrevious').click(function () {
});
});
Hope this helps.

disable button in ascx page prior to postback

How do I disable a button in an ascx page? I know how to do it on an aspx page with:
btnSave.Attributes.Add("onclick",
"this.disabled=true;this.value='Please Wait...';needToConfirm=false;" +
ClientScript.GetPostBackEventReference(btnSave, "").ToString());
But the ClientScript function is not present in the ascx page.
You don't need the ClientScript in code behind, you can also have it directly in the button tag as OnClientClick attribute:
<asp:Button id="btnSave" runat="server" OnClientClick="this.disabled=true; this.value='Please Wait...'; needToConfirm=false;" Text="Save" />
You can access the ClientScript property using Page.ClientScript from your user control (ascx).
you can access ClientScript through the Page property of your control
Page.ClientScript.GetPostBackEventReference(btnSave, "")
Did you try: Page.ClientScript.GetPostBackEventReference?
Here's how I fixed the problem. In every page, I have three divs:
<div align="center" id="divWait" style="display:none"><asp:Label ID="lblSaveorCancel" runat="server"></asp:Label></div>
<div style="display:block" id="divMain">
---- page actual content here ------
</divMain>
<div id="divBut" style="text-align:center;display:block">
<asp:button id="SaveBtn" runat="server" CssClass="button" Text="Save" OnClientClick="return Validate('save');"/>
<asp:button id="CancelBtn" runat="server" CssClass="button" Text="Cancel" OnClientClick="return ShowWaitDiv('cancel');"/>
</div>
And then I added scripts:
function Validate(saveorcancel) {
----- validation checks for data on the page ------
}
function ShowWaitDiv(saveorcancel) {
var div = document.getElementById(divWait.id);
div.style.display = "block";
var div1 = document.getElementById(divMain.id);
div1.style.display = "none";
var div2 = document.getElementById(divBut.id);
div2.style.display = "none";
if (saveorcancel == 'save') {
document.getElementById('<%= lblSaveorCancel.ClientID %>').innerHTML = 'Saving data, please wait...';
}
else {
document.getElementById('<%= lblSaveorCancel.ClientID %>').innerHTML = 'Redirecting, please wait...';
}
return true;
}
Simple, quick, and the user sees the result of clicking a button immediately and cannot click any buttons again.

how to clear an label value in javascript

I have an label "test" comimg from .cs [c# code] text="data saved successfully" . but once I click the save button i need to clear its text
right now I have 3 required field validators. with message [cannot be blank, cannot be blank,cannot be blank,] as user as clicked the save button I need to clear the text of the label. But need to show the required fields validator message
any idea how to solve it
thank you
make a javascript function like:
<Script type="text/javascript">
function clearText(cntId) {
var cnt = document.getElementById(cntId);
cnt.value ="";
return false;
}
</script>
then on your submit button attach a client side event
<asp:Button id='btnSubmit' Text='Submit' onClientClick='clearText("<%this.lblLable.ClientId%>");' .... />
On the client-side use a script like this
<script type="text/javascript">
function clearLabelValue(){
var labelObj = document.getElementById("<%= myLabel.ClientID %>");
labelObj.value = "";
}
</script>
<asp:Label id="myLabel" runat="server" Text="Some text"/>
<asp:Button id="myButton" runat="server" Text="Submit" OnClientClick="clearLabelValue();return false;"/>
Didn't test it in detail, but should work.
It is not really clear what you want to achieve, although I have the feeling there may be a "better" (more standard compliant) way of achieving what you want. Maybe you could describe more clearly what you want, so we may be able to help you.
In these situations when a particular button has validation attached to it and also we need to fire some javascript what is done is to define a javascript function which is called on click of save button.
What this javascript function does:
This function will take your label and will set its value as blank so that the text is cleared.
Now in order to validate the page which happens internally (in case the javascript function is not written on the save button click) we need to explicitly call what asp.net call for client side validation.
There is a function page_ClientValidate which needs to be called from this javascript function so that validation is still done and we also do some other processing like clearing the label in this case.
<!--for cleaning to label ; -->
document.getElementById("MyLabel").innerHTML = "";
<!--and label is like;-->
<asp:Label ID="MyLabel" runat="server" ></asp:Label>
You can simply achieve this using below script:
<script type="text/javascript">
function clearLabelValue(){
document.getElementById("<%= myLabel.ClientID %>").innerText=""
}
</script>
<asp:Label ID="myLabel" runat="server" ></asp:Label>
<asp:Button id="myButton" runat="server" Text="Submit" OnClientClick="clearLabelValue();"/>

ASP.NET WebForms - Keeping contextual focus on Button controls

Consider the following:
<form runat="server">
<div>
<asp:TextBox runat="server" ID="tb1" />
<asp:Button runat="server" ID="b1" OnClick="b1_Click" />
</div>
<div>
<asp:TextBox runat="server" ID="tb2" />
<asp:Button runat="server" ID="b2" OnClick="b2_Click" />
</div>
<div>
<asp:TextBox runat="server" ID="tb3" />
<asp:Button runat="server" ID="b3" OnClick="b3_Click" />
</div>
</form>
Each TextBox has an associated Button. I want to be able to switch the focus on each of these Button controls, so that when I place my cursor in the 2nd textbox (tb2) and press Enter, the associated button (b2) gets clicked and the associated OnClick event gets fired.
I've got a few ideas myself, but I'd like you guys' feedback/lessons-learned before I start potentially wasting time on implementing a broken solution.
NOTE:
Using the HTML fieldset element is not an option--Some of the interfaces are very complex.
There can be multiple inputs associated with one button.
You could trap the keydown event on the Textbox and then fire the button's callback javascript if it's the enter key. You can get the callback reference using ClientScriptManager.GetPostBackEventReference
Alternatively you could wrap every textbox in it's own Panel, which exposes a DefaultButton property.
Well you could do a nice simple route using jQuery if you are using it.
Simply doing the following might work nicely:
<script language="javascript" type="text/javascript">
jQuery(function(){
jQuery('input').keydown(function(e){
if (e.keyCode == 13) {
jQuery(this).next().trigger('click');
return false;
}
});
});
</script>
And then code side you would have the relevant event handler triggered, or just simply see which button was clicked by querying the sender object id

Resources