Just like the title says. I have some javascript on a page that is supposed to fire a __doPostBack call if other variables/conditions on the form are valid.
function DoPostBack() {
var valid = true;
if (SomethingHappens) {
valid = false
}
alert("Is_Valid? " + valid) //evaluates to true
if (valid) {
__doPostBack("btnSubmit",''); //First click here does nothing, despite it being it by code. Works fine the second time.
}
And that is hooked up to a button as follows:
<input ID="btnSubmit" runat="server" onclick="DoPostBack();" type="button" value="Submit" style="width:80px"/>
What is causing the first click of the submit button to be ignored? I have confirmed that this is the behavior I am seeing by placing a breakpoint in my page_load event. The first time __doPostBack is called, the breakpoint is not hit, the second time, it is hit.
If what you are saying is correct, your function should get executed, since it is not, then at least something you have said is not true.
Related
I have an input form, with a submit button. I don't want the user to be able to double click the submit button and double submit the form...
So I have added the following jQuery to my Form:
var prevSubmitTime = new Date('2000-01-01');
function preventFromBeingDoubleSubmitted() {
$('form').each(function () {
$(this).submit(function (e) {
if ($("form").valid()) {
var curSubmitTime = new Date($.now());
// prevent the second submit if it is within 2 seconds of the first submit
if (curSubmitTime - prevSubmitTime < 2000) {
e.preventDefault();
}
prevSubmitTime = new Date($.now());
}
});
});
}
$(document).ready(function () {
preventFromBeingDoubleSubmitted();
});
The above code stores the submit time and prevents the second submit, if it is too early (less than 2 seconds), I don't want to permanently disable the submit button, in case there is a server side error...
This code does what I want, but when debugging the code, I can never hit a break point on e.preventDefault();... even if I double click the submit button.
It looks like the second submit event is waiting for the first submit event to complete before firing.
But, if I remove preventFromBeingDoubleSubmitted() function, then I would be able to double submit the form, by double clicking the submit button.
Can anyone explain why sometimes the submit events are fired immediately one after the other... and sometimes it is not the case? Does putting the event handler inside .each(), affects their execution behavior?
Form's when submited by default navigate to the set action url. In the case it isn't explicitly set the url is the current page. The first submit call is going end up starting the navigation process. During this the currently loaded javascript code gets unloaded. This includes event handlers. Hence why you get the inconsistency of being able to double submit or not. If the network request, and other page processes, to the action url happens faster than the speed it takes you to click again the event handlers and your break point won't be called/reached again because they are already unloaded. And vise versa if the network request is slower you would be able to cause the handler to be called and the break point to be reached (if it hasnt already been unloaded).
You say you don't want to permanently disable the submit button, but even if you disable it the form submission is going to cause a page change, and in your example's case this will just load the same page with a new submit button which will not be disabled anymore because its a new page. Thus it is never really permanetly disabeled in the first place.
Now if your real form isn't actually doing a normal form submit, and you are using something like an ajax request, web socket connection, etc then you would set the button to disabled(or set a busy flag) before the request and unset it in the ajax request callback, web socket event,etc.
For example:
jQuery('form').on('submit',function(e){
e.preventDefault();
var fd = new FormData(this);
jQuery('yourbutton').prop('disabled',true);
fetch('url',{method:"post",body:fd}).then(()=>jQuery('yourbutton').prop('disabled',false));
});
In your snippet I've added a few logs that might be helpful. As you are asking more than one question, I'll answer one by one.
var prevSubmitTime = new Date('2000-01-01');
function preventFromBeingDoubleSubmitted() {
$('form').each(function () {
$(this).submit(function (e) {
console.log('I am going to submit form');
if ($("form").valid()) {
var curSubmitTime = new Date($.now());
console.log('I am a valid form')
// prevent the second submit if it is within 2 seconds of the first submit
if (curSubmitTime - prevSubmitTime < 2000) {
console.log('A small time difference. So I am stopping')
e.preventDefault();
}
prevSubmitTime = new Date($.now());
}
});
});
}
$(document).ready(function () {
preventFromBeingDoubleSubmitted();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.0/jquery.validate.js"></script>
<form id="myform">
<input type="text" name="q" required="required" />
<br />
<input type="text" name="bar" required="required" />
<br />
<br />
<input type="submit" />
</form>
Can anyone explain why sometimes the submit events are fired
immediately one after the other... and sometimes it is not the case?
I think you've answered this question yourself. You are adding the code to check if there a difference between time you clicked the submit button the first time versus the second time. If the time difference exists, then you stop the second form submit.
I can never hit a break point on e.preventDefault();
The reason you're not able to get the console is, you're redirecting away from that page when you click the submit button. So the console is cleared. If you want to see the console, use an ajax function to submit the form. And on return, you can probably redirect the page somewhere.
Does putting the event handler inside .each(), affects their execution
behavior?
No. It is just an iterator. It will not affect the submit functionality.
I've added a link to the jsfiddle. Adding the alert before preventDefault will stop page from redirecting momentarily. This will prove that the execution happened.
http://jsfiddle.net/2vugwyfe/
You solution is way too overcomplicated. The easiest way to prevent a double submit would be to disable the submit button on submission.
Example:
var submittable = false;
$('form').submit(function (e) {
if (!submittable) {
e.preventDefault();
var $this = $(this);
var $submitButton = $this.find('button[type="submit"]');
$submitButton.attr('disabled', true);
if (CONDITION_SATISFIED) {
submittable = true;
$this.submit()
} else {
$submitButton.attr('disabled', false);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<button type="submit">Submit</button>
</form>
If you add e.preventDefault(); just before doing $("form").valid(), you will see there's an error thrown.
script.js:7 Uncaught TypeError: $(...).valid is not a function
at HTMLFormElement.<anonymous> (script.js:7)
at HTMLFormElement.dispatch (jquery.min.js:2)
at HTMLFormElement.y.handle (jquery.min.js:2)
This error wasn't visible at first because the submit actually changes the page (refreshes the page in this case) if nothing else is implemented.
However, in general the practice is navigating to another page after a form submission.
If you still want to go with your approach and limit the number of submitting, I suggest keeping the submitted state in a local variable and change it according to the validation on the server side.
Last thing.. I don't understand the iteration through the forms since you have only one in your HTML -> $('form').each is useless.
I know what you want, but you made it very complicated. instead of inserting a submit button just add a simple div and add a click handler on that.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="myform">
<input type="text" name="myInput" />
<div id="submit" onclick="myform_submit()" />
</form>
and :
function myform_submit() {
if ($('#submit').hasClass('busy')) { return; }
$('#submit').addClass('busy');
// do the tasks then remove the `busy` class :
$('#submit').removeClass('busy');
}
I just show the idea, you can do better.
I am working on an asp.net web forms project. I have an asp.net button which has both OnClientClick and onClick events. The OnClientClick event executes the javascript function processHolidayDates() which in turn shows a Telerik's Ok/Cancel message box. When the Ok button is clicked it will return true and if the Cancel button is clicked it will return false. So, when false is returned, I don't want the button click event to execute the server side code. However, the moment the message box is displayed already the code behind under the btnCreate_Click is executed. When I add "return false;" at the OnClientClick as in "OnClientClick="javascript:processHolidayDates(); return false " , the code behind is never executed even if I chose Ok in the message box. The following is my code on the aspx page
<asp:button id="btnCreate" runat="server" Text="Create" OnClientClick="javascript:processHolidayDates(); " onclick="btnCreate_Click"></asp:button>
function processStartAndEndDates() {
var oConfirm = radconfirm('Hello', callBackFn, 400, 300, null, 'Test');
return oConfirm ;
}
You could change your OnClientClick to
OnClientClick="return processHolidayDates();"
So that you will return false (and cancel the postback) if the user cancels the window.
This should work:
OnClientClick="return processHolidayDates();"
I've seen a few examples on how to do this but they don't seem to be working for me. Having said that, I am doing it a little differently than the examples I've seen so I'm not sure if what I'm trying to do is possible.
I have a multiline asp texbox and onclientclick I want to make sure (among other things) the user hasn't gone over on max length before I submit the onclick event. However, this textbox is part of a user control that will be used X number of times on the page so I can't just grab the control from the Javascript. I have to send the clientID from the code behind. So I'm adding the OnClientClick event on the codebehind and pass the clientID for the control there. I wonder if that's why I'm getting the results I'm getting.
SaveNoteButton.OnClientClick = string.Format("return BeforeSave('{0}');", NoteTextBox.ClientID);
<asp:Button runat="server" CssClass="casenotes-bluebuttons" ID="SaveNoteButton" Text="Save" OnClick="SaveNoteButton_Click" Enabled="false" />
function BeforeSave(noteCtrl) {
var txt = document.getElementById(noteCtrl);
if (txt.value.length > 500) {
alert("false");
return false;
}
else {
alert("true");
return true;
}
}
So in theory, the OnClientClick property is added to the SaveNoteButton button. When it's fired, it passes the NoteTextBox.ClientID, the js checks the textbox length, returns true or false then the OnClick event fires depending on the return value. But it doesn't. I even tried wrapping the method call in an alert and the method is in fact returning what I expect but the OnClick event isn't firing regardless of the method's return value. I even tried removing the method call and hardcoding true and it still doesn't fire. So I know the return value is true and yet no OnClick love.
Oddly enough, it was syntax on the call to the js method.
SaveNoteButton.OnClientClick = string.Format("return BeforeSave('{0}');", NoteTextBox.ClientID);
becomes
SaveNoteButton.OnClientClick = string.Format("BeforeSave('{0}')", NoteTextBox.ClientID);
and it works just fine.
Remove the Enabled="false" bit. This is why the onclick event does not fire.
Alright, this is what I did to solve the problem:
SaveNoteButton.OnClientClick = string.Format("if(!BeforeSave('{0}', '{1}')) return false;", NoteTextBox.ClientID, this._maxLength);
How to set the Onbeforeunload Function on the specific button?
Example, I have 3 buttons.
<div>
<asp:Button ID="btnBack" runat="server" Text="Back" CssClass="po-font" Height="30px"/>
<asp:Button ID="btnSumbit" runat="server" Text="Submit" CssClass="po-font" Height="30px"/>
<asp:Button ID="btnSaveToDraft" runat="server" Text="Save To Draft" CssClass="po-font" Height="30px"/>
</div>
On javascript, I did something like:
<script type="text/javascript">
window.onbeforeunload = confirmExit;
function confirmExit()
{
return "Are you sure you want to leave this page? Any unsaved progress will be lost";
}
</script>
The function will work properly though but I want to specify the function in an specific button probably on the "Back" button. I did something like.
<script type="text/javascript">
function confirmExit()
{
return "Are you sure you want to leave this page? Any unsaved progress will be lost";
}
$('#btnBack').live('click', function () {
window.onbeforeunload = confirmExit;
});
</script>
but Id doesn't work. How to do this? Any Ideas? I just want to trigger the function on the specified button. Help me.
Use $('<%=btnBack.ClientID%>').click(function(){...}); because asp.net prefix its own client with the control id and html rendered id may look like ct100$btnBack.
First off its unlikely that the ID is correct as ASP.NET prefixes the ID with the containers if that object. Either give btnBack a class and use that or:
$("[id$='btnBack']").on("click",...)
I'll edit with a battle tested version when I'm back in front of my pc
* Edit to add battle tested code *
So you need to bind the unload event to the window, you can't assign a function to it as Kevin says in his answer. If you only want it to fire for a specific button, the code below is something I use in active production (it has a few more checks, and checks if anything has been changed on a page before firing etc...), so should work for you:
if (self == top) { // Check we're not in an iFrame or colorbox
$(window).bind("beforeunload", function (event) { // bind the window unload event
if (backLinkClicked) { // Check if the back link has been clicked, if so prompt
return "Are you sure you want to leave this page? Any unsaved progress will be lost";
};
});
}
Then your click handler:
var backLinkClicked = false;
$("[id$='btnBack']").click(function() { backLinkClicked = true });
So you back button click handler just changes the variable to fire the prompt on unload.
First off, you should understand that onbeforeunload is an event, and by putting:
window.onbeforeunload = confirmExit;
you are attaching an event handler to window, which will be global.
If I am correct, what you want is bringing up a confirmation dialog when user tries to navigate away by clicking on a button. I suggest you try this:
$('#<%=btnBack.ClientID%>').on('click', function (e) {
// check if user clicked cancel
if (!confirm("Are you sure [...]") {
e.stopImmediatePropagation();
e.preventDefault();
return false;
}
});
With this, when user clicks the button, a confirmation dialog will appear (confirm()). If user clicks cancel, code will call stopImmediatePropagation() (which should prevent other JS event handler from running) and preventDefault() (which disable the default action when the button is clicked, e.g., submitting the form).
I haven't tested this out myself, but I guess it should work.
Here is code:
<form method="post" id="cp_ind_form">
// lots of input fields!
<input type="submit" name="update_submit" value="Update" />
<input type="submit" name="delete_submit" value="Delete" onclick="deleteConfirm()" />
</form>
scripts.js (confirmed that this file is connected to above page)
(function deleteConfirm() {
var s = document.getElementById('confirm');
s.onchange = function() {
var yes = confirm('Do you really want to delete this location?');
if (yes) {
var f = document.getElementById('cp_ind_form');
f.submit();
}
}
})();
}
This is driving me insane. Such a basic function is not working here? I am basically copying it from other code that I have that DOES work, and this is no different. Can someone confirm if I am missing a small detail?
Look at the code.
You are adding an onchange event to something when you click the submit.
You are not triggering the confirm to be shown, and you are not cancelling the original submission.
AND it makes no sense to have it wrapped with (funciton(){})();
It should be
function deleteConfirm() {
return confirm('Do you really want to delete this location?');
}
and
onclick="return deleteConfirm();"
To actually execute the confirm when deleteConfirm is called, change your code to this:
function deleteConfirm() {
var yes = confirm('Do you really want to delete this location?');
if (yes) {
document.getElementById('cp_ind_form').submit();
}
// block default submit
return(false);
}
This also returns false so that the default form submission doesn't happen.
Then, change your HTML to this:
onsubmit="return deleteConfirm()"
If you handle the onsubmit instead of onclick, you can block the default submit by returning false from the handler.
deleteConfirm() is run on button click. Inside this function you are assigning code to the eventonchange which than waits for the item #confirm to be changed. I don't know where is that element but I pressume the event is never fired so the confirm box never shows