I'm trying to stop postback on form submit if my custom jQuery validation returns false.
Is there any way to prevent the __doPostback() function finishing from within the submit() function?
I'd assumed:
$('#aspnetForm').submit(function () { return false; });
would do the trick, but apparently that's not the case: does anyone have a suggestion?
The submit() function does block the postback (it won't postback if you pause at a breakpoint in firebug), but I can't seem to stop the event happening after the submit() function is complete!
Cheers, Ed
EDIT
OK, I had a quick mess about and discovered that the fact that the button I'm using to cause the postback is tied to an updatepanel as an asyncpostbacktrigger seems to be the problem: If I remove it as a trigger (i.e. cause it to product a full postback), the is no problem preventing the postback with return false;
Any ideas why the async postback would not be stoppable using return false?
You have to use the client side PageRequestManager to properly handle AJAX submit events. (e.g. prevent an async postback.)
If you are not in total control of the page, there can be JavaScript on the page that just calls __doPostBack() without going through any page logic.
In this case - in addition to the above -, you have to store the old window.__doPostBack() and provide your own - as #tucaz mentioned in his comments.
(...and as you mentioned, it can get quite perplexing with chaining.)
For regular submits (non-AJAX), you can provide an event handler as others have pointed out.
This page might be of help and has some code samples that use PageRequestManager. In particular:
initialize : function()
{
...
this._onSubmitHandler = Function.createDelegate(this, this._onSubmit);
this._onPartialUpdateEnd = Function.createDelegate(this, this._onUpdateEnd);
if (typeof(Sys.WebForms)!== "undefined" && typeof(Sys.WebForms.PageRequestManager)!== "undefined")
{
Array.add(Sys.WebForms.PageRequestManager.getInstance()._onSubmitStatements, this._onSubmitHandler);
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(this._onPartialUpdateEnd);
}
else
$addHandler(document.forms[0], "submit", this._onSubmitHandler);
},
Edit:
Following the above, this, for example works fine for me (.Net 3.5 SP1, Button1 is trigger in the updatepanel, etc...):
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.4.2.js" charset="utf-8"
type="text/javascript"></script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<div>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
</div>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Button1" />
</Triggers>
</asp:UpdatePanel>
</form>
<script type="text/javascript">
(function($, undefined) {
var submitHandler = function(e) {
return false;
}
if (typeof (Sys.WebForms) !== "undefined" && typeof (Sys.WebForms.PageRequestManager) !== "undefined") {
Array.add(Sys.WebForms.PageRequestManager.getInstance()._onSubmitStatements, submitHandler);
} else {
$("form").submit(submitHandler);
}
})(jQuery);
</script>
</body>
</html>
$('#yourPostButton').click(function(){
return false;
});
This should do!
Related
I'm trying to have two things happen when I click on a button in an ASP.NET page:
Change the text in an ASP:Label.
Disable the button.
I've done a lot of research on this, but I've had difficulties doing either.
For #1, I thought that this should work, but it doesn't:
<%# Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
Protected Sub BtnSubmit_Click(sender As Object, e As System.EventArgs)
Label1.Text = "Working..."
System.Threading.Thread.Sleep(5000)
Label1.Text = "Done."
End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Test Page</title>
</head>
<body>
<form id="form1" runat="server">
<ajaxToolkit:ToolkitScriptManager runat="server" />
<div>
<asp:ListBox runat="server" Height="100px" />
<br />
<asp:UpdatePanel runat="server">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="BtnSubmit" EventName="Click" />
</Triggers>
<ContentTemplate>
<asp:Label ID="Label1" runat="server" Text="Press the button" />
</ContentTemplate>
</asp:UpdatePanel>
<br />
<asp:Button runat="server" ID="BtnSubmit" OnClick="BtnSubmit_Click" Text="Submit Me!" />
</div>
</form>
</body>
</html>
The "Working..." message is never displayed.
As for #2, I added this to the button (I forget where I found it):
OnClientClick="this.disabled = true; this.value = 'Working...';"
UseSubmitBehavior="false"
That had the desired effect of disabling the button and changing its text (value), but it wasn't possible to change it back using Text and Enabled properties.
I just found a solution on msdn (http://msdn.microsoft.com/en-us/library/bb386518.aspx). Added some code and remove some unnecessary parts.
<%# Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void btnDoWork_Click(object sender, EventArgs e)
{
/// do something long lasting
System.Threading.Thread.Sleep(3000);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<script language="javascript" type="text/javascript">
<!--
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_initializeRequest(InitializeRequest);
prm.add_endRequest(EndRequest);
var postBackElement;
function InitializeRequest(sender, args) {
if (prm.get_isInAsyncPostBack()) {
args.set_cancel(true);
}
postBackElement = args.get_postBackElement();
if (postBackElement.id == 'btnDoWork') {
$get('btnDoWork').value = 'Working ...';
$get('btnDoWork').disabled = true;
}
}
function EndRequest(sender, args) {
if (postBackElement.id == 'btnDoWork') {
$get('btnDoWork').value = 'Done!';
$get('btnDoWork').disabled = false;
}
}
// -->
</script>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Label ID="Label1" runat="server" Text="Hello World!"></asp:Label><br />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnDoWork" />
</Triggers>
</asp:UpdatePanel>
<asp:Button ID="btnDoWork" runat="server" Text="Start!" OnClick="btnDoWork_Click" />
</div>
</form>
</body>
</html>
What you basically do, is you register some eventHandler for Initialize_ and End_Request - in those you disable and enable your button!
HTH
ASP will not flush the result to the browser while working even if you use an UpdatePanel. It will finish the jobb (including the sleep) before flushing.
You can use a UpdateProgress to show the "Working.." text.
<asp:UpdateProgress>
This will show its content while the UpdatePanel is working. Once the UpdatePanel is finished, the content will disappear.
What you need in you ClickEvent is:
Label1.Text = "Done."
btnSubmit.Enabled = false
This will show the Done text and disable the button. And tell the UpdateProgress to disappear.
The Working message is never displayed because you are executing the script on the server, which doesn't respond to the client until the method exits.
ASP.NET AJAX has a built in control for displaying messages like this while the UpdatePanel is waiting on the server.
Check out the UpdateProgress Control:
<asp:UpdateProgress runat="server" id="progress" ><ProgressTemplate>Working...</ProgressTemplate></asp:UpdateProgress>
You can disable the button by setting the Enabled property to false in your server-side method.
BtnSubmit.Enabled = false
#1: You will never see the message "Working" as you stopped the thread .... Every Message will be shown when your process has "ended".
#2: you coded clientSide to disable the button, there is no code to re-enable your button
hth
First off, "working" never appears because the final value of the label at the time of post-back is "Done." Think about what is happening here - you click the button which causes a post-back to the server. It processes the post-back which includes running the button click code, the result of which is then sent back to the browser. Your 'working' text never makes it back over the wire.
I am not clear on what you're trying to accomplish with the client-side code, but to do what you describe you're almsot there server-side:
Protected Sub BtnSubmit_Click(sender As Object, e As System.EventArgs)
Label1.Text = "Done."
btnSubmit.Enabled = false
End Sub
Also, but your button inside your update panel template tags so it participates in the ajax-postback.
I've tried to wrap up my problem with a complete example below - the original problem is part of a jQuery plug-in that I'm writing to extend the behaviour of an ASP.NET ajax application I already have.
The aspx page below has one drop down list which is marked for auto post back. I've also bound a change event using jquery (which ultimately I will swap for a .live() event to maintain the binding after the update panel refresh.) The problem is, when the jQuery event is bound I see two ajax begin requests and page_loads fire but only one ddlTest_OnselectedIndexChanged event. One of the page loads is malformed too - the content-length states it's about 300 bytes long whilst the totalBytes is 0 and form data empty. This does not happen if I bind to the click event of a button.
Can someone explain why the erroneous page_load event is firing please??
<%# Page Language="C#" AutoEventWireup="true" %>
<%# Import Namespace="System.Diagnostics" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<script runat="server">
private void Page_Load(object sender, EventArgs e)
{
Debug.WriteLine(Request.Headers["Content-Length"]);
Debug.WriteLine(Request.TotalBytes);
Debug.WriteLine(Request.Form.ToString());
Debugger.Break();
}
private void ddlTest_OnSelectedIndexChanged(object sender, EventArgs e)
{
Debugger.Break();
}
</script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
<script type="text/javascript" language="javascript">
$(document).ready(function() {
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(beginRequestHandler);
$("#<%=ddlTest.ClientID%>").change(function() { alert('jQuery binding fired'); });
});
function beginRequestHandler() {
alert("Started ajax call");
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="SciptManager" runat="server" />
<asp:UpdatePanel ID="updTest" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:DropDownList ID="ddlTest" runat="server" AutoPostBack="true" OnSelectedIndexChanged="ddlTest_OnSelectedIndexChanged" >
<asp:ListItem>First</asp:ListItem>
<asp:ListItem>Second</asp:ListItem>
</asp:DropDownList>
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
Update : I've narrowed the problem down even further. Firefox and Chrome both work as I would expect whilst IE is having a problem. I've also simplified the erroneous code to the example below. It's hard to believe it's this simple but the jQuery .change() method on the drop down list triggers the onchange event on the select element twice! I'll look for other people who've had this problem and report back my findings!
<%# Page Language="C#" AutoEventWireup="true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
<script type="text/javascript" language="javascript">
$(document).ready(function() {
$('#ddlTest').change(function() { alert('jQuery event fired'); });
});
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:DropDownList id="ddlTest" runat="server" onchange="alert('element event');">
<asp:ListItem Text="First" />
<asp:ListItem Text="Second" />
</asp:DropDownList>
</form>
</body>
</html>
The call of $("#<%=ddlTest.ClientID%>").change(... is probably trigger your drop down list and because of your autopostBack, you get an second refresh of your page.
It looks like I've uncovered a bug in the latest version of jQuery :(. If I change the test back to version 1.3.2 it works fine! I've also found a reference to a bug raised with jQuery.
Take out the autopostback=true = it is firing one postback and the change event is another.
<asp:RadioButtonList ID="RdoBtnHasNotified" runat="server" RepeatDirection="Horizontal" AutoPostBack="True" OnSelectedIndexChanged="RdoBtnHasNotified_SelectedIndexChanged">
<asp:ListItem Value="1">Yes</asp:ListItem>
<asp:ListItem Value="0" Selected="True">No</asp:ListItem>
</asp:RadioButtonList>
<asp:TextBox ID="TxtHowNotified" runat="server" TextMode="MultiLine" MaxLength="100"></asp:TextBox>
I want to enable the TextBox by clicking on the RadioButtonList, without using autopostback=true. How can I do this with JavaScript?
You can use jQuery to manipulate input's enabled state (HTML translation for TextBox) or you can use ASP.NET Ajax so you can set both controls inside of update panel in this case you won't see page being reloaded on postback which must happen in order for you to change status of TextBox on some other event.
Tbh i would go with ASP.NET Ajax because my experience shows that jQuery does not work that well with ASP.NET controls when it comes to complex stuff ie. ASP.NET uses javascript for event activation which can cause either jQuery or ASP.NET not to work as you may expected.
Good luck with update panels...
Using jQuery, you can have a fairly custom result by hooking in to the changes on the radio buttons...
$("#<%= RdoBtnHasNotified.ClientID %> > input[type=radio]").change(function(){
// this function is called whenever one of the radio button list's control's change
// the $(this) variable refers to the input control that triggered the event
var txt = $("#<%= TxtHowNotified.ClientID %>");
if($(this).val()=="1") {
txt.removeAttr("disabled");
} else {
txt.attr("disabled", true);
}
});
Each ListItem renders a radio button with the same name parameter; I would suggest running the app and looking at the generated source to get an idea of what you need to do to listen for the radio button events. Essentially the ID of the radio button list is the name parameter, so you can get the group of radio buttons as (using JQuery):
$("input[name='<%= rbl.ClientID%>']").click(function() {
var tb = $("#textboxid");
//do something here; this points to the radio button
});
HTH.
Here you go:
<%# Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void RdoBtnHasNotified_PreRender(object sender, EventArgs e)
{
foreach (ListItem item in RdoBtnHasNotified.Items)
item.Attributes.Add("onclick", string.Format("toggleTextBox(this,'{0}');", TxtHowNotified.ClientID));
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script type="text/javascript">
function toggleTextBox(radioButton, textBoxId) {
document.getElementById(textBoxId).disabled = radioButton.value != "1";
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:RadioButtonList ID="RdoBtnHasNotified" OnPreRender="RdoBtnHasNotified_PreRender"
runat="server" RepeatDirection="Horizontal">
<asp:ListItem Value="1">Yes</asp:ListItem>
<asp:ListItem Value="0" Selected="True">No</asp:ListItem>
</asp:RadioButtonList>
<asp:TextBox ID="TxtHowNotified" runat="server" TextMode="MultiLine" MaxLength="100" Enabled="false"></asp:TextBox>
</div>
</form>
</body>
</html>
Write the code in the following way
<script type="text/javascript">
$(document).ready(function() {
$("input[name='RdoBtnHasNotified']").change(function() {
$("input[name='RdoBtnHasNotified']:checked").val() == '1' ? $('#TxtHowNotified').removeAttr("disabled") : $('#TxtHowNotified').attr('disabled', 'true');
});
});
</script>
and also disable the textbox (Enabled="false") since initialy the value of the "RdoBtnHasNotified" is "No".
$('#<%= RdoBtnHasNotified.ClientID %> > input[type=radio]').click(function()
{
var txtbox = $('#<%= TxtHowNotified.ClientID %>');
if($(this).val() == '1')
{
document.getElementById('#<%= TxtHowNotified.ClientID %>').disabled = false;
}
else
{
document.getElementById('#<%= TxtHowNotified.ClientID %>').disabled = true;
}
});
I think using change event will not fire in IE.
Hi I'm facing a weird problem that only happens in FF. I have a TextBox control with OnTextChanged handler. The event handler is working fine most of the time, but when the user changed the text and press Enter in FF, the OnTextChanged event is called twice. I observed the problem in Firebug that the first request is actually canceled because of the second event.
Test.aspx
<%# Page Language="C#" AutoEventWireup="True" CodeFile="~/Test.aspx.cs" Inherits="T.Test" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Custom TextBox - OnTextChanged - C# Example</title>
</head>
<body>
<form id="Form1" method="post" runat="server">
<asp:ScriptManager runat="server" ID="SM">
</asp:ScriptManager>
<h3>Custom TextBox - OnTextChanged - C# Example</h3>
<asp:UpdatePanel runat="server" ID="Panel1">
<ContentTemplate>
<asp:Panel runat="server" ID="Panel2">
<asp:TextBox ID="TextBox1" AutoPostBack="true" OnTextChanged="OnTextChanged" runat="server">Hello World!
</asp:TextBox>
</asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
Test.aspx.cs
using System;
using System.Web.UI;
namespace T
{
public partial class Test : Page
{
protected void OnTextChanged(object sender, EventArgs e)
{
var a = 0;
}
}
}
Put a break point # var a, and you'll be able to see that after changing text and press enter in FF (v3.5.7), the OnTextChanged event is invoked twice.
So my question is, what's the best way to properly handle OnTextChanged event so that hitting enter in the textbox doesn't trigger double postback.
Regards,
I don't know why it's isolated to FireFox, but if you remove the AutoPostBack property, that will solve the problem.
There is also an explanation here of why it's posting back twice.
I know its an old thread but maybe helpful for others.
I had the same issue when validating the text entered. I was getting 2 events fired so I put this script at the top of the page which causes the enter to just tab to the next control instead of submitting the form. The text box remained the same AutoPostBack="true" OnTextChanged="xxx_TextChanged"
''''
<script type="text/javascript">
$('body').on('keydown', 'input, select', function (e) {
if (e.key === "Enter") {
var self = $(this), form = self.parents('form:eq(0)'), focusable, next;
focusable = form.find('input,a,select,button,textarea').filter(':visible');
next = focusable.eq(focusable.index(this) + 1);
if (next.length) {
next.focus();
} else {
form.submit();
}
return false;
}
});
</script>
''''
I've got a page where I have a ModalPopUpExtender which I want to show from code.
This is my site structure which is a web form within a nested masterpage:
...
<asp:Content ID="con" ContentPlaceHolderID="mainContent" runat="server">
<asp:MultiView ID="tabMultiView" runat="server">
<asp:View ID="generalTab" runat="server">
<asp:ScriptManager ID="scriptManager" runat="server">
</asp:ScriptManager>
<ajaxToolkit:ModalPopupExtender ID="newAddressModalPopup" CancelControlID="newAddressDialogCancelButton"
BackgroundCssClass="modalBackground" TargetControlID="newAddressLink" PopupControlID="newAddressDialogDiv"
runat="server">
</ajaxToolkit:ModalPopupExtender>
...
open dialog
<script type="text/javascript">
function openNewAddressDialog() {
$find('<%= newAddressModalPopup.ClientID %>').show();
}
</script>
...
The find method always returns null. I also tried findComponent, etc. It's always null. When I debugged the method I noticed that the components collection (which is kind of a dictionary with the control ID as key) is empty.
What could the problem be? BTW, I am using jQuery stuff on the page as well.
Thanks a lot!
Ok I found it. The TargetControl was not rendered in HTML because it was in another view.
In your JavaScript function try using document.getElementById("ctl00_ContentPlaceHolder1_newAddressModalPopup"). Maybe it works. Let me know if you get issues.
Or try Setting BehaviorID="someid" to the modal popupextender and use this JavaScript code:
function changeValue()
{
var myBehavior = $find("myBehavior1");
myBehavior.show();
}
Or:
var modalDialog = $find("newAddressModalPopup");
// Get reference to modal popup using the Ajax API $find() function.
if (modalDialog != null) {
modalDialog.show();
}