I'm working with jQuery and I have implemented a button click handler. To test, I have been setting a console output with the contents "test". However, when clicking on the button, the output appears in the console, but only for a brief moment before disappearing again. That repeats every time the button is clicked.
JS code:
$(document).ready(function () {
$("#go").click(function () {
console.log("test");
});
});
HTML code:
<form class="navbar-form navbar-right">
<button id="go" class="btn btn-default">Go</button>
</form>
Is there a solution to this?
That's because the button submits the form and reloads the entire page in your browser. Cancel the default action of this button by returning false from your click handler if you want to stay on the same page and continue executing some javascript code:
$(document).ready(function () {
$("#go").click(function () {
console.log("test");
return false;
});
});
If you do not cancel the default action, the browser will simply redirect away leaving no time for any javascript stuff to run.
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 have disabled page redirects/reloads with window.beforeunload function, but once the form submission happens in the page, I want to redirect to the next page, without showing the window.beforeunload alerts. How can I do that?
$(window).on("beforeunload", function () {
return "Changes won't be saved.";
});
This is the button that shouldn't trigger the alert:
<form id="command" action="/some-uri" method="post">
<button type="submit" value="NEXT" class="btn btn-red- light">NEXT</button>
</form>
Check a variable
pseudo code
if some dirty change -> window.hasSomeDirtyChanges = true;
if all dirty changes saved -> window.hasSomeDirtyChanges = false;
$(window).on("beforeunload", function () {
if(!window.hasSomeDirtyChanges) return true;
return "Changes won't be saved.";
});
So this way you don't have to bind unbind every time you go to a page. This will work for all the pages, you just need to manage a variable.
add a class to every element that you don't want to trigger the event, for example ".not-trigger", then:
$(".not-trigger").on("click", function(){
$(window).off("beforeonunload");
});
I'm still a newb when it comes to MVC, Ajax and JavaScript. I have an application where I have to make a change. Right now, when a change is made and the Save, the spinner displays as the info saves and the page loads. The code for the Save looks like this:
$('#SaveButton').on('click', function () {
navParams.isDirty = false;
});
HTML looks like this:
<input type="submit" value="Save" class="btn btn-block btn-primary user-action" name="action:Save" id="SaveButton" />
Just a note there multiple buttons on the screen so it is using the "Multiple Button" solution from How do you handle multiple submit buttons in ASP.NET MVC Framework?
The following code was added:
$('#SaveButton').on('click', function () {
navParams.isDirty = false;
displaySavePromptMessage();
});
function displaySavePromptMessage() {
if (isModalOpen == false) {
bootbox.dialog({
closeButton: false,
title: "",
message: "<strong>Warning: </strong>Changes have been made, ensure corresponding dates have been updated on the screen",
buttons: {
success: {
label: "Ok",
callback: function () {
navParams.userAction = false;
}
}
}
});
}
}
Now what's happening is the save button is clicked, the spinner starts running, the dialog box loads, but before the OK button is clicked the dialog button closes and the spinner stops. The changes are saved.
What needs to happen is the spinner starts, the dialog box loads and everything stays as is until the user clicks OK. Then the processing continues. I'm not sure how to make this happen. Any thoughts?
Basic concept. You need to listen to submit event and prevent it:
$('.some-form').on('submit', function(submitEvent) {
submitEvent.preventDefault();
});
Then in your handler, you need to submit your form on success:
// Inside your success handler
$('.some-form').get(0).submit();
You have input type="submit" which will submit the form when this button is clicked. Either change this to type="button" or as #Lesha Ogonkov said
$('#yourFormID').on('submit', function (e) {
e.preventDefault();//it will stop loading page on form submission
});
in ajax inside you success handler function
$('.myFromID').get(0).submit();
I have a simple HTML button on my form, with script as follows:
$(document).ready(function () {
$("#btn1").click(function () {
$("#btn1").text("Button clicked");
return false;
});
});
With the return false, it works as I expect - I click the button, and its text changes to 'Button clicked'. Without the 'return false', it changes, but then changes back.
Complete JQuery noob here, why do I need the 'return false'?
A <button> in a form submits the form, which is why it turns back, the page reloads resetting everything javascript changed, so you see the change, and it immediately reloads the page when the form submits.
The return false prevents the form from submitting when clicking the button.
Note: the <button> element has a default type of submit, so it will always submit the form it's nested inside.
Like #adeneo said, your form is being sent out so the page will reload. Additionally, if you don't want to use return false; you can use preventDefault() by passing an event parameter to your function as such:
$(document).ready(function () {
$("#btn1").click(function (ev) {
ev.preventDefault();
$("#btn1").text("Button clicked");
});
});
Hope this helps,
If the <button> was not intended to submit the form, then instead of using return false; or other workarounds make the button the proper type.
<button id="btn1" type="button">
And it will stop submitting when clicked. The reason it does now is because the button's default type is submit (it has 3 possible types: submit, button, and reset).
The custom CSS class .btn-loading disables the button and sets its text to loading state:
$(document).on('click', '.btn-loading', function() {
var btn = $(this);
btn.button('loading');
// Fail-safe for buttons that get stuck in the loading state sometimes.
setTimeout(function() {
Rollbar.error("Button stuck");
btn.button('reset');
}, 10000);
});
// Be sure to remove any loading state on page refresh
$(document).on('ready page:load', function() {
$('.btn-loading').button('reset');
});
Example button
button type="submit" class="btn btn-primary btn-loading" data-loading-text="Processing..." Continue
When the button is pressed, text is changed to 'Processing...' and the button is disabled preventing multiple submits.
However, sometimes in development and production, the button gets stuck in the loading state and for some reason does not cause the submit and/or rendering of the new page. The setTimeout is firing multiple times a day on the production server. We are having hard times producing the problem on the development consistently.. it happens randomly now and then.
Rollbar's statistics shows that it's not browser specific nor a single button+action that's causing it. So the cause is not a slow server response either.
Any idea what might be causing this and how to fix it?
I faced similar problem some time back and solved the same with a different approach. Try to follow the below steps to solve your problem.
HTML:
Change your button type from “Submit” to “Button”. This will give you full control to execute your scripts.
<button type="button" class="btn btn-default" id=”SubmitButton”>Submit</button>
JQUERY:
On Button Click, you need to disable the button. This will immediately stop users to click again. Then you can change the button text to "Processing". Below script will guide you make it happen.
$(function () {
$('#SubmitButton').click(function (e) {
e.preventDefault();
//Disable Button to avoid multiple clicks
$(this).attr("disabled", true);
// Change the button text to “Processing”
$(this).text(‘Processing’);
// Write Your Validation Scripts
// If Validation Fails - $(this).text(‘Submit’); $(this).attr("disabled", '');
// Else Submit Form
//Submit the Form
$("#targetForm").submit();
})
})
To prevent multiple submit you can use $.one() function also. and add remaining logic.
When the button is pressed, text is changed to 'Processing...' and the
button is disabled preventing multiple submits.
-- Note that there's not part in your code snippet that disables the button.
// Fail-safe for buttons that get stuck in the loading state sometimes.
setTimeout(function() {
// if(stuck){
Rollbar.error("Button stuck");
btn.button('reset');
// } // end-if
}, 10000);
-- It looks like your fallback will always be executed. Shouldn't be executed when the button is stuck?
The setTimeout is firing multiple times a day on the production
server.
-- Because your button is never disabled, and because there is no condition restricting it from firing on being clicked.
Moreover, there's no jQuery method like button(). It looks like you're using jQueryUI, which you should have mentioned as well. But jQueryUI + Bootstrap seem like a weird combination, to me.