Preventing rapid submission button clicks? - c#

I found a solution like this but my onclick event is already tied to a code-behind handler:
MyButton.Attributes.Add("onclick", "this.disabled=true;" + Page.ClientScript.GetPostBackEventReference(MyButton, "").ToString());
onclick="this.disabled=true;__doPostBack('MyContrl$MyButton','');"
My code:
<asp:imagebutton id="CheckoutBtn" runat="server" ImageURL="Styles/Images/submit.gif" onclick="CheckoutBtn_Click">
code-behind:
protected void CheckoutBtn_Click(object sender, ImageClickEventArgs e)
{
{
MyShoppingCart usersShoppingCart = new MyShoppingCart();
if (usersShoppingCart.SubmitOrder(User.Identity.Name) == true)
{
CheckOutHeader.InnerText = "Thank you.";
Message.Visible = false;
CheckoutBtn.Visible = false;
}
else
{
CheckOutHeader.InnerText = "Submission Failed - Please try again. ";
}
}
}

Disabling the Button serverside won't work, the Button will be disabled AFTER the PostBack, in this time the user can still click several times, disabling it in JavaScript this.disabled=true; is the only way to successfully do this.

Cases where you are trying to prevent the user from submitting a form multiple times are best handled using the Post/Redirect/Get pattern.
It is a very simple pattern and Wikipedia does a good job of explaining it:
http://en.wikipedia.org/wiki/Post/Redirect/Get

I assume you want to skip clicks that come within a certain TimeSpan of previous clicks. Create a class variable "DataTime LastClickTime", initially set to DateTime.MinValue. When you enter the click handler, check if DateTime.Now - LastClickTime > TimeSpan(...desired...) and if it isn't, exit the click handler with a return.

Try to disable the button with javascript instead of disabling it server side?
<asp:imagebutton id="CheckoutBtn" runat="server" ImageURL="Styles/Images/submit.gif" onclick="CheckoutBtn_Click" OnClientClick="this.disabled=true;">

One way is hide the button from Javascript and show some ajax loader image.
function btnClientClick()
{
document.getElementById('CheckoutBtn').style.display = 'none';
document.getElementById('dvLoader').style.display = '';
}

Related

Why doesn't asp.net button work?

I have used this behind asp button click function. It works on local system but not after begin deployed on server. Why ?
public void EmployeeDeActivation()
{
hdnfieldSessionPersonalInfoID.Value = "0";
Session["ExtraPersonalInfoID"] = 0;
Response.Redirect("EmployeeInformation.aspx", false);
}
.aspx code:
<asp:Button ID="btnEmployeeActivated" runat="server" Visible="false" OnClick="btnEmployeeActivated_Click"
CssClass="btn btn-rounded pull-right btnEmployeeActivated" />
i.e. when i click button when on local system, it hits then button event and refrehes the page but when it doesn't work like then button click never hits.
Update:
protected void btnEmployeeActivated_Click(object sender, EventArgs e)
{
try
{
EmployeeDeActivation();
}
catch (Exception ex)
{
throw;
}
}
Doesn't this method need to accept an event handler? E.g.
protected virtual void OnClick(
EventArgs e
)
Also, the part of code where you set your hidden is not needed as you redirect after.
Also it has the wrong name as it doesn't match the onclick name
Try to enable Trace and log on every method in the page. Try to visualize what your code is doing during postback.
Another useful tool is Glimpse.
Hope it helps!
asp button property "Visible" is set to false in your code. how come button is rendering at first place ?

Client Interaction in WebForms

What way is standard/ recommended to do the following:
When a user raises the Page_Command "Save" or "Send," I want to run a method. If the method returns false, I want to send the user back to the page and display a message.
All of the data they entered in the form should still be there. The message would have a button that reads, "Send Anyway/ Regardless." If they click it, it will send.
I know I could do this via a webservice and jQuery, but I am asking how I would do this via WebForms.
Here is my basic code:
protected void Page_Command(Object sender, CommandEventArgs e)
{
if ( e.CommandName == "Save" || e.CommandName == "Send" )
{
// run method
}
}
There are several ways you could do this.
One option might be to a button with the text "Save", and another with the text "Send anyway". Make the second button invisible to begin with, and the first visible.
When the first button is clicked, it should run the validation-logic. If validation succeeds, submit - otherwise, hide the first button, and set the other one to visible.
When / if the second button is clicked, the submit is performed without validation.
Update:
With some minor modifications, you should be able to do something like this:
Markup:
<asp:Button runat="server"
ID="myFirstButton"
OnClick="SubmitWithValidation" />
<asp:Button runat="server"
ID="mySecondButton"
Visible="False"
OnClick="SubmitData" />
Code:
protected void SubmitWithValidation(object sender, EventArgs e)
{
if (ValidateMyData())
{
SubmitData(sender, e);
}
else
{
mySecondButton.Visible = true;
myFirstButton.Visible = false;
}
}
private bool ValidateMyData()
{
// Validate stuff
return isValid;
}
private void SubmitData(object sender, EventArgs eventArgs)
{
// Logic to submit your data here
}

Disabling a button doesn't fire click event on server side

I have an imagebutton in my aspx page like:
<asp:ImageButton ID="btnProcessPayment" ImageUrl="~/Images/process-payment.png" OnClientClick="return disableButton(this);"
runat="server" OnClick="btnProcessPayment_Click" />
This is my javascript function:
function disableButton(button) {
button.disabled = true;
return true;
}
As you can see in my javascript event handler I have disabled the button to prevent the user from click the button twice. However, even my server side event handler doesn't get fired due to this. What am I doing wrong?
Note: If I comment out this line button.disabled = true; all works out pretty well.
Disabling the button disables the form submit as well. You need to do the submit yourself:
function disableButton(button) {
button.disabled = true;
__doPostBack(<%= btnProcessPayment.ClientID %>,''); // need to manually submit
return true;
}
Updated as per Waqas suggestion!
You need to fire out serverside event of the button some thing like this
onclick="this.disabled=true;__doPostBack('buttonclientid','');"
or
function disableButton(button) {
button.disabled = true;
__doPostBack('buttonclientid','');
return true;
}
Use this and it worked for me
__doPostBack('<%= btnSubmit.ClientID %>', '');
where btnSubmit is the ID of my button and I wanted to trigger the server side click event for the button. It works.

How to skip Validating after clicking on a Form's Cancel button

I use C#.
I have a Windows Form with an edit box and a Cancel button. The edit box has code in validating event. The code is executed every time the edit box loses focus. When I click on the Cancel button I just want to close the form. I don't want any validation for the edit box to be executed. How can this be accomplished?
Here is an important detail: if the validation fails, then
e.Cancel = true;
prevents from leaving the control.
But when a user clicks Cancel button, then the form should be closed no matter what. how can this be implemented?
If the validation occurs when the edit box loses focus, nothing about the the cancel button is going to stop that from happening.
However, if the failing validation is preventing the cancel button from doing its thing, set the CausesValidation property of the button to false.
Reference: Button.CausesValidation property
Obviously CausesValidation property of the button has to be set to false and then the validating event will never happen on its click. But this can fail if the parent control of the button has its CausesValidation Property set to true. Most of the time developers misses/forgets to change the CausesValidation property of the container control (like the panel control). Set that also to False. And that should do the trick.
I was having problems getting my form to close, since the validation of certain controls was stopping it. I had set the control.CausesValidation = false for the cancel button and all the parents of the cancel button. But still was having problems.
It seemed that if the user was in the middle of editing a field that was using validation and just decided to give up (leaving the field with an invalid input), the cancel button event was being fired but the window would not close down.
This was fixed by the following in the cancel button click event:
private void btnCancel_Click(object sender, EventArgs e)
{
// Stop the validation of any controls so the form can close.
AutoValidate = AutoValidate.Disable;
Close();
}
Set the CausesValidation property of the Cancel button to false.
Set the CausesValidation property to false.
None of these answers quite did the job, but the last answer from this thread does. Basically, you need to:
Insure that the Cancel button (if any) has .CausesValidation set to false
Override this virtual method.
protected override bool ProcessDialogKey(Keys keyData) {
if (keyData == Keys.Escape) {
this.AutoValidate = AutoValidate.Disable;
CancelButton.PerformClick();
this.AutoValidate = AutoValidate.Inherit;
return true;
}
return base.ProcessDialogKey(keyData);
}
I didn't really answer this, just pointing to the two guys who actually did.
Setting CausesValidation to false is the key, however this alone is not enough. If the buttons parent has CausesValidation set to true, the validating event will still get called. In one of my cases I had a cancel button on a panel on a form, so I had to set CausesValidation = false on the panel as well as the form. In the end I did this programatically as it was simpler than going through all the forms...
Control control = cancelButton;
while(control != null)
{
control.CausesValidation = false;
control = control.Parent;
}
In my case, in the form I set the property AutoValidate to EnableAllowFocusChange
By using Visual Studio wizard you can do it like that:
Judicious use of the Control.CausesValidation property will help you achieve what you want.
Just above the validation code on the edit box add:
if (btnCancel.focused)
{
return;
}
That should do it.
In complement of the answer of Daniel Schaffer: if the validation occurs when the edit box loses focus, you can forbid the button to activate to bypass local validation and exit anyway.
public class UnselectableButton : Button
{
public UnselectableButton()
{
this.SetStyle(ControlStyles.Selectable, false);
}
}
or if you use DevExpress:
this.simpleButtonCancel.AllowFocus = false;
Note that doing so will change the keyboard experience: the tab will focus anymore on the cancel button.
Maybe you want to use BackgroundWorker to give little bit delay, so you can decide whether validation should run or not. Here's the example of avoiding validation on form closing.
// The flag
private bool _isClosing = false;
// Action that avoids validation
protected override void OnClosing(CancelEventArgs e) {
_isClosing = true;
base.OnClosing(e);
}
// Validated event handler
private void txtControlToValidate_Validated(object sender, EventArgs e) {
_isClosing = false;
var worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerAsync();
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
// Do validation on complete so you'll remain on same thread
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (!_isClosing)
DoValidationHere();
}
// Give a delay, I'm not sure this is necessary cause I tried to remove the Thread.Sleep and it was still working fine.
void worker_DoWork(object sender, DoWorkEventArgs e) {
Thread.Sleep(100);
}
This is an old question however I recently ran into this issue and solved it this way:
1st, we are loading a UserControl into a 'shell' Form that has a save and cancel button. The UserControl inherit an interface (like IEditView) that has functions for Save, Cancel, Validate and ToggleValidate.
In the shell form we used the mouse enter and mouse leave like so:
private void utbCancel_MouseEnter(object sender, EventArgs e)
{
((Interface.IEdit)tlpMain.Controls[1]).ToggleValidate();
}
private void utbCancel_MouseLeave(object sender, EventArgs e)
{
((Interface.IEdit)tlpMain.Controls[1]).ToggleValidate();
}
Then in ToggleValidate (Say a simple form with two controls...you can always just loop through a list if you want) we set the CausesValidation
public bool ToggleValidate()
{
uneCalcValue.CausesValidation = !uneCalcValue.CausesValidation;
txtDescription.CausesValidation = !txtDescription.CausesValidation;
return txtDescription.CausesValidation;
}
Hope this helps.
I found this thread today while investigating why my form would not close when a validation error occurred.
I tried the CausesValidation = false on the close button and on the form itself (X to close).
Nothing was working with this complex form.
While reading through the comments I spotted one that appears to work perfectly
on the form close event , not the close button (so it will fire when X is clicked also)
This did the trick.
AutoValidate = AutoValidate.Disable;
Create a bool:
bool doOnce;
Set it to false in your function and then:
if (doOnce == false)
{
e.cancel = true;
doOnce = true;
}
This means it will only run once and you should be able to cancel it. This worked for me anyways.
This work for me.
private void btnCancelar_MouseMove(object sender, MouseEventArgs e)
{
foreach (Control item in Form.ActiveForm.Controls)
{
item.CausesValidation = false;
}
}

How do I dynamically create/remove controls, with EventHandlers, to/from an ASP.NET page?

In one of my projects I need to build an ASP.NET page and some of the controls need to be created dynamically. These controls are added to the page by the code-behind class and they have some event-handlers added to them. Upon the PostBacks these event-handlers have a lot to do with what controls are then shown on the page. To cut the story short, this doesn't work for me and I don't seem to be able to figure this out.
So, as my project is quite involved, I decided to create a short example that doesn't work either but if you can tweak it so that it works, that would be great and I would then be able to apply your solution to my original problem.
The following example should dynamically create three buttons on a panel. When one of the buttons is pressed all of the buttons should be dynamically re-created except for the button that was pressed. In other words, just hide the button that the user presses and show the other two.
For your solution to be helpful you can't statically create the buttons and then use the Visible property (or drastically change the example in other ways) - you have to re-create all the button controls dynamically upon every PostBack (not necessarily in the event-handler though). This is not a trick-question - I really don't know how to do this. Thank you very much for your effort. Here is my short example:
From the Default.aspx file:
<body>
<form id="form1" runat="server">
<div>
<asp:Panel ID="ButtonsPanel" runat="server"></asp:Panel>
</div>
</form>
</body>
From the Default.aspx.cs code-behind file:
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace DynamicControls
{
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
AddButtons();
}
protected void AddButtons()
{
var lastClick = (string) Session["ClickedButton"] ?? "";
ButtonsPanel.Controls.Clear();
if (!lastClick.Equals("1")) AddButtonControl("1");
if (!lastClick.Equals("2")) AddButtonControl("2");
if (!lastClick.Equals("3")) AddButtonControl("3");
}
protected void AddButtonControl(String id)
{
var button = new Button {Text = id};
button.Click += button_Click;
ButtonsPanel.Controls.Add(button);
}
private void button_Click(object sender, EventArgs e)
{
Session["ClickedButton"] = ((Button) sender).Text;
AddButtons();
}
}
}
My example shows the three buttons and when I click one of the buttons, the pressed button gets hidden. Seems to work; but after this first click, I have to click each button TWICE for it to get hidden. !?
I think that you have to provide the same ID for your buttons every time you add them like this for example (in first line of AddButtonControl method):
var button = new Button { Text = id , ID = id };
EDIT - My solution without using session:
public partial class _Default : Page
{
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
AddButtons();
}
protected void AddButtons()
{
AddButtonControl("btn1", "1");
AddButtonControl("btn2", "2");
AddButtonControl("btn3", "3");
}
protected void AddButtonControl(string id, string text)
{
var button = new Button { Text = text, ID = id };
button.Click += button_Click;
ButtonsPanel.Controls.Add(button);
}
private void button_Click(object sender, EventArgs e)
{
foreach (Control control in ButtonsPanel.Controls)
control.Visible = !control.Equals(sender);
}
}
You need to make sure that your dynamic controls are being added during the Pre_Init event.
See here for the ASP.NET Page Lifecycle: http://msdn.microsoft.com/en-us/library/ms178472.aspx
When adding events you need to do it no later than the Page_Load method and they need to be added every single request, ie you should never wrap event assignment in a !IsPostBack.
You need to create dynamic controls ever single request as well. ViewState will not handle the recreation on your behalf.
One thing I notice is that when you click a button you are invoking AddButtons() twice, once in the Page_Load() and once in the button_Click() method. You should probably wrap the one in Page_Load() in an if (!IsPostBack) block.
if (!IsPostBack)
{
AddButtons();
}
AFAIK, creating of controls should not be placed in Page_Load but in Page_PreInit (ViewState and SessionState is loaded before Page_Load but after Page_PreInit).
With your problem, I would suggest to debug the AddButtons function to find out what exactly (and when) is stored in Session["ClickedButton"]. Then, you should be able to figure out the problem.
the controls that are added dynamically are not cached so this migth me one of your problems

Categories

Resources