Submit function executing multiple times when using jQuery - javascript

I am having a file upload form where I am checking the file size through javascript before finally submitting the form. The form is working fine and when I try to upload a file more than the mentioned size then it shows the correct alert at the first time. But if I again click on upload without selecting another file I get the same alert twice. If I again repeat the process I get the alert 3 times. Below is the code
<script>
var flag=0;
$('#filename').bind('change', function() {
var filesiz = this.files[0].size;
if (filesiz >10485760)
{flag=1;}
else
{flag=0;}
});
function upfunc(){
$('#smalldata').hide();
$('#invalidfile').hide();
$('#invalidfile9').hide();
if($( "#UserComments" ).hasClass( "textAreaField valid" ) && $( "#filename" ).hasClass( "valid" )){
$('#loading_image').show(); // show animation
$( "#uploadsfrm" ).submit(function() {
if(flag==1)
{alert ('File size cannot exceed 10 MB.');
$('#loading_image').hide();
return false;
//event.preventDefault();
}
else
return true;
});
}
}
</script>
I think the error may be because I am using bind. Any help would be really appreciated.Thank you

You have a multi event calling in here.
Every time you call upfunc() you attach a Submit event.
you might consider either declaring Submit event once or use $( "#uploadsfrm" ).unbind('submit') before the
$( "#uploadsfrm" ).submit(function()....
so in fact, first call you will have 1 event listener, 2nd call you will attach another event, which now sums up to 2..there until infinite.
e.preventProgration or StopDefault wont help because its the same object and therefor it wont stop the calling of the events.
Even if it will help, it is just a piece of bad code :(

Related

JavaScript event handling code get's called multiple times

I need your help. I'm currently working with a modal lib in JavaScript to display a modal for my customers:
https://github.com/vodkabears/Remodal/tree/1.1.1
Unfortunately my event handling in case the user clicks a button don't works like expected. When you take a look into the manual, you can see under the point Events the following event handler:
$(document).on('cancellation', '.remodal', function () {
console.log('Cancel button is clicked');
});
This one get's triggered for example when the cancel button get's pressed. Because I'm using one popup for multiple things, I need to attach the event handler to the call directly. So first I've wrote a function that opens the popup:
function openRemodal( remodalId ) {
let remodal = $( `[data-remodal-id=${remodalId}]` );
remodal.remodal().open();
return remodal; // <- added to handle events
}
I can call this function that way:
openRemodal( 'information-remodal' );
To get an event handling done, I've now returned the remodal in the function and re-wrote my call:
openRemodal( 'information-remodal' ).on( 'cancellation', function () {
alert( 'Test' );
} );
This seems to work but somehow when I repeat the opening of the popup and pressing the button, the alert get's shown multiple times increased by any new opening.
I'm not sure why this happens and why. Can you please help me get this working? I just want to call any function in there once - any time.
JQuery has a .one method ... try using that in place of .on. The callback should run only once. https://api.jquery.com/one/
On each time when you open model you attach function to cancelation event. so add new function and you never remove it. after first time you have one, then you have two... etc.
just attach it once, or remove it after handling event.
const modal = openRemodal( 'information-remodal' )
const handler = () => {
alert( 'Test' );
modal.off('cancellation', handler);
}
modal.on( 'cancellation', handler);

Any event triggered on autocomplete?

I have a pretty simple form. When the user types in an input field, I want to update what they've typed somewhere else on the page. This all works fine. I've bound the update to the keyup, change and click events.
The only problem is if you select an input from the browser's autocomplete box, it does not update. Is there any event that triggers when you select from autocomplete (it's apparently neither change nor click). Note that if you select from the autocomplete box and the blur the input field, the update will be triggered. I would like for it to be triggered as soon as the autocomplete .
See: http://jsfiddle.net/pYKKp/ (hopefully you have filled out a lot of forms in the past with an input named "email").
HTML:
<input name="email" />
<div id="whatever"><whatever></div>
CSS:
div {
float: right;
}
Script:
$("input").on('keyup change click', function () {
var v = $(this).val();
if (v) {
$("#whatever").text(v);
}
else {
$("#whatever").text('<whatever>');
}
});
I recommending using monitorEvents. It's a function provide by the javascript console in both web inspector and firebug that prints out all events that are generated by an element. Here's an example of how you'd use it:
monitorEvents($("input")[0]);
In your case, both Firefox and Opera generate an input event when the user selects an item from the autocomplete drop down. In IE7-8 a change event is produced after the user changes focus. The latest Chrome does generate a similar event.
A detailed browser compatibility chart can be found here:
https://developer.mozilla.org/en-US/docs/Web/Events/input
Here is an awesome solution.
$('html').bind('input', function() {
alert('test');
});
I tested with Chrome and Firefox and it will also work for other browsers.
I have tried a lot of events with many elements but only this is triggered when you select from autocomplete.
Hope it will save some one's time.
Add "blur". works in all browsers!
$("input").on('blur keyup change click', function () {
As Xavi explained, there's no a solution 100% cross-browser for that, so I created a trick on my own for that (5 steps to go on):
1. I need a couple of new arrays:
window.timeouts = new Array();
window.memo_values = new Array();
2. on focus on the input text I want to trigger (in your case "email", in my example "name") I set an Interval, for example using jQuery (not needed thought):
jQuery('#name').focus(function ()
{
var id = jQuery(this).attr('id');
window.timeouts[id] = setInterval('onChangeValue.call(document.getElementById("'+ id +'"), doSomething)', 500);
});
3. on blur I remove the interval: (always using jQuery not needed thought), and I verify if the value changed
jQuery('#name').blur(function ()
{
var id = jQuery(this).attr('id');
onChangeValue.call(document.getElementById(id), doSomething);
clearInterval(window.timeouts[id]);
delete window.timeouts[id];
});
4. Now, the main function which check changes is the following
function onChangeValue(callback)
{
if (window.memo_values[this.id] != this.value)
{
window.memo_values[this.id] = this.value;
if (callback instanceof Function)
{
callback.call(this);
}
else
{
eval( callback );
}
}
}
Important note: you can use "this" inside the above function, referring to your triggered input HTML element. An id must be specified in order to that function to work, and you can pass a function, or a function name or a string of command as a callback.
5. Finally you can do something when the input value is changed, even when a value is selected from a autocomplete dropdown list
function doSomething()
{
alert('got you! '+this.value);
}
Important note: again you use "this" inside the above function referring to the your triggered input HTML element.
WORKING FIDDLE!!!
I know it sounds complicated, but it isn't.
I prepared a working fiddle for you, the input to change is named "name" so if you ever entered your name in an online form you might have an autocomplete dropdown list of your browser to test.
Detecting autocomplete on form input with jQuery OR JAVASCRIPT
Using: Event input. To select (input or textarea) value suggestions
FOR EXAMPLE FOR JQUERY:
$(input).on('input', function() {
alert("Number selected ");
});
FOR EXAMPLE FOR JAVASCRIPT:
<input type="text" onInput="affiche(document.getElementById('something').text)" name="Somthing" />
This start ajax query ...
The only sure way is to use an interval.
Luca's answer is too complicated for me, so I created my own short version which hopefully will help someone (maybe even me from the future):
$input.on( 'focus', function(){
var intervalDuration = 1000, // ms
interval = setInterval( function(){
// do your tests here
// ..................
// when element loses focus, we stop checking:
if( ! $input.is( ':focus' ) ) clearInterval( interval );
}, intervalDuration );
} );
Tested on Chrome, Mozilla and even IE.
I've realised via monitorEvents that at least in Chrome the keyup event is fired before the autocomplete input event. On a normal keyboard input the sequence is keydown input keyup, so after the input.
What i did is then:
let myFun = ()=>{ ..do Something };
input.addEventListener('change', myFun );
//fallback in case change is not fired on autocomplete
let _k = null;
input.addEventListener( 'keydown', (e)=>_k=e.type );
input.addEventListener( 'keyup', (e)=>_k=e.type );
input.addEventListener( 'input', (e)=>{ if(_k === 'keyup') myFun();})
Needs to be checked with other browser, but that might be a way without intervals.
I don't think you need an event for this: this happens only once, and there is no good browser-wide support for this, as shown by #xavi 's answer.
Just add a function after loading the body that checks the fields once for any changes in the default value, or if it's just a matter of copying a certain value to another place, just copy it to make sure it is initialized properly.

jQuery preventDefault() doesn't work like I expect - is this a jQuery Bug?

This is simplified code to exactly reproduce a problem I'm having with jQuery.
I would expect it to cancel the original click, then trigger the click event again which in turn would cause the browser to load the href of the url.
<script type="text/javascript">
$( function()
{
var confirmed = false;
$('a').click( function( event )
{
if ( confirmed == false )
{
event.preventDefault();
confirmed = true;
$(event.target).trigger( 'click' );
}
});
});
</script>
Original Question Here
I do not want to change window.location. I want to trigger so that any event handlers that have been bound to the click event will fire too. It just so happens that I also want the browser to follow the link.
.trigger('click') won’t trigger the browser’s default action — it will just trigger jQuery event handlers bound to that event on that element.
Take a look at this answer — you need to create and fire a click event yourself. Here’s the code from that answer:
function fireEvent(obj,evt){
var fireOnThis = obj;
if( document.createEvent ) {
var evObj = document.createEvent('MouseEvents');
evObj.initEvent( evt, true, false );
fireOnThis.dispatchEvent( evObj );
} else if( document.createEventObject ) {
var evObj = document.createEventObject();
fireOnThis.fireEvent( 'on' + evt, evObj );
}
}
Your event handler will always be run when you trigger a "click" event, and before the default behavior happens. So no, it's not a bug.
edit — If you want the default action to happen when the element is clicked and your various conditions are satisfied, just return from your handler.
$('a').click( function( event )
{
if ( confirmed == false )
{
event.preventDefault();
confirmed = true;
}
else
return;
});
When your handler returns, the browser will carry on with the default behavior.
edit again — and of course if you want to simply carry out programmatically the default action of an <a> tag with an "href" attribute, it's just:
window.location = $(element).attr('href');
No need for a "click" event at all.
preventDefault() doesn't cancel the jquery bound click action; it cancels the 'default' click action that is inherent to an anchor tag. unbind() is the proper function for canceling any action/function that is bound to an object.
It looks like you have one state where you want to inhibit the default action (and update a flag), and another state where you simply want the default action to apply. Wouldn't removing the else case entirely do the trick? With no preventDefault() the default click action will still run.
Edit: Pointy's answer now shows your code updated similarly.
Edit: I'm still not entirely sure what you're going for, but if for some reason you must trigger manually, one way to prevent a stack overflow due to recursion would be to assign a custom event (i.e., not click), and then always suppress the default action. Then in your conditional, either do or don't fire the custom event.
So, something like this (untested):
$('a')
.bind('fancyclick', function () { // Your special click logic
changeStatusOf( confirmed );
doCrazyStuff();
location.replace( $(this).attr('href') ); // or whatever
})
.click( function (e) {
e.preventDefault(); // Always suppress natural click
if ( confirmed ){
$(this).trigger('fancyclick'); // Fire the special click
}
});
I'll simply write while I analyse, hoping it'll be easy to follow and easy to compare to your code. Kick me when I can optimize/enhance my replies in any way.
checking - part 1
Move the "preventDefault" outside of the "if" statement! If you don't move it outside of the "if", the code will skip the "preventDefault" if confirmed == true.
<script type="text/javascript">
$( function()
{
var confirmed = false;
$('a').click( function( event )
{
event.preventDefault();
if ( confirmed == false )
{
confirmed = true;
$(event.target).trigger( 'click' );
}
});
});
</script>
checking - part 2
Besides that, I'm wondering about the existence of "var confirmed" in general. The code would also work flawless without it since you're not using the confirmed variable in the function anywhere else...
<script type="text/javascript">
$( function()
{
$('a').click( function( event )
{
event.preventDefault();
$(event.target).trigger( 'click' );
});
});
</script>
checking - part 3
Knowing you can replace the trigger with a simple click, did you try that?
<script type="text/javascript">
$( function()
{
$('a').click( function( event )
{
event.preventDefault();
$(event.target).click();
});
});
</script>
checking - part 4
If the click still fails on the target element, it's definitely time to inspect (using "FireBug on Firefox" or alike) if "event.target" holds an object at all. You never know...
checking - part 5
One more thing: I don't see any Document Ready checking, so I hope you've put that script at the end of your file, right before the "</body>" tag. If you load it in the "<head>" without checking Document Ready, it might happen that javascript tries to bind the event to an element that is yet to be loaded into the dom... which would be like throwing feathers against a 9 Inch steel plate... nothing will happen. ;)
that's all
That's all that comes to mind as an answer to your question. One of them could fix the issue you're having. At least, that's what I hope. These little snippets here at stackoverflow leave massive probabilities related to what we don't see. It's hard to be sure what might be missing when you don't have the "complete view". ;)
How about doing something like creating a link offscreen that would handle the final click? That way, you can prevent the click of the original link, handle the code, then proceed to trigger the click of the hidden copy.

Call a function after form reset

Is there a method for me to call a function after click on the reset button in form, and I mean after, so that the form is first reset and then my function called. Normal event bubbling would call my function and only then reset the form. Now I would like to avoid setTimeout in order to do this.
What I need is to call a function when a form is reset because I use uniform and uniform needs to be updated when values change.
At the moment I do it like this:
//Reset inputs in a form when reset button is hit
$("button[type='reset']").live('click', function(){
elem = this;
//Sadly we need to use setTimeout to execute this after the reset has taken place
setTimeout(function(){
$.each($(elem).parents('form').find(":input"), function(){
$.uniform.update($(this));
});
}, 50);
});
I tried to do al this on $(':input').change() but reseting an element does not seem to trigger the change event.
Thank you in advance for any help.
HTML forms do have an onReset event, you can add your call inside there:
function updateForm()
{
$.each($('form').find(":input"), function(){
$.uniform.update($(this));
});
}
<form onReset="updateForm();">
As pointed out in the comment by Frédéric Hamidi you can also use bind like so:
$('form').bind('reset', function() {
$.each($(this).find(":input"), function(){
$.uniform.update($(this));
});
});
After some testing it appears both ways fire before the reset takes place and not after. The way your doing it now appears to be the best way.
The same conclusion was found in this question here
I haven't yet tested in all browsers, but you can do your own ordering within a click event:
http://jsfiddle.net/vol7ron/9KCNL/1/
$(document).ready(function() {
$("input:reset").click(function() { // apply to reset button's click event
this.form.reset(); // reset the form
window.alert($("input:text").val()); // call your function after the reset
return false; // prevent reset button from resetting again
});
});
Time ago I worked debugging a Google IE related plugin and I solved the main error with a bubbling trick. That's why I think immediately in this solution for your problem (of course should be cross-browser):
<form>
<div id="capture_bubble">
<input type="text"><input type="reset">
</div>
</form>
In this way you can capture the bubbling with $('#capture_bubble') after reset event be triggered.
You can make a quick test with:
(function($) {
$(function() {
$('#capture_bubble').live('click', function(){
console.debug('capture_bubble');
alert('capture_bubble')
})
$("input[type='reset']").live('click', function(){
this.form.reset(); // forcing reset event
console.debug('reset');
alert('reset')
});
});
})(jQuery);
Please note: this.form.reset(); (change made due to a jeff-wilbert observation)
you shouldn't need to wait 50 milliseconds. If you use setTimeout with a timeout of zero, it effectively means "push this code onto the event stack". Since the form-reset is guaranteed to have fired first, the code in the setTimeout is guaranteed (in well behaved javascript interpreters) to have access to the form values you want (post-reset). You should be able to use the code below, guilt-free.
var afterReset = function(){
var pushMeOntoTheEventStack = window.setTimeout(function(){
$("#form input").each(function(){
console.log( this.name + ' = ' + this.value );
});
},0);
};
$("#form").on("reset",afterReset);
Try this solution
Goal:
add on "click" event
prevent the default action (reset)
trigger "reset"
run desired code
Example:
$("button[type='reset']").on('click', function(evt) {
evt.preventDefault();
$(evt.target).trigger('reset');
// enter code to run after reset
$.each($(this).find(":input"), function(){
$.uniform.update($(this));
});
});

Debounce clicks when submitting a web form

A poorly-written back-end system we interface with is having trouble with handling the load we're producing. While they fix their load problems, we're trying to reduce any additional load we're generating, one of which is that the back-end system continues to try and service a form submission even if another submission has come from the same user.
One thing we've noticed is users double-clicking the form submission button. I need to de-bounce these clicks, and prevent a second form submission.
My approach (using Prototype) places an onSubmit on the form that calls the following function which hides the form submission button and displays a "loading..." div.
function disableSubmit(id1, id2) {
$(id1).style.display = 'none';
$(id2).style.display = 'inline';
}
The problem I've found with this approach is that if I use an animated gif in the "loading..." div, it loads fine but doesn't animate while the form is submitting.
Is there a better way to do this de-bouncing and continue to show animation on the page while waiting for the form result to (finally) load?
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Using Prototype, you can use this code to watch if any form has been submitted and disable all submit buttons when it does:
document.observe( 'dom:loaded', function() { // when document is loaded
$$( 'form' ).each( function( form ) { // find all FORM elements in the document
form.observe( 'submit', function() { // when any form is submitted
$$( 'input[type="submit"]' ).invoke( 'disable' ); // disable all submit buttons
} );
} );
} );
This should help with users that double-click on submit buttons. However, it will still be possible to submit the form any other way (e.g. pressing Enter on text field). To prevent this, you have to start watching for any form submission after the first one and stop it:
document.observe( 'dom:loaded', function() {
$$( 'form' ).each( function( form ) {
form.observe( 'submit', function() {
$$( 'input[type="submit"]' ).invoke( 'disable' );
$$( 'form' ).observe( 'submit', function( evt ) { // once any form is submitted
evt.stop(); // prevent any other form submission
} );
} );
} );
} );
All good suggestions above. If you really want to "debounce" as you say, then I've got a great function for that. More details at unscriptable.com
var debounce = function (func, threshold, execAsap) {
var timeout;
return function debounced () {
var obj = this, args = arguments;
function delayed () {
if (!execAsap)
func.apply(obj, args);
timeout = null;
};
if (timeout)
clearTimeout(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = setTimeout(delayed, threshold || 100);
};
}
If you've got jQuery handy, attach a click() event that disables the button after the initial submission -
$('input[type="submit"]').click(function(event){
event.preventDefault();
this.click(null);
});
that sort of thing.
You could try setting the "disabled" flag on the input (type=submit) element, rather than just changing the style. That should entirely shut down the from on the browser side.
See: http://www.prototypejs.org/api/form/element#method-disable
Here I have a simple and handy way to prevent duplicate or multiple form submittion.
Give a class "prevent-mult-submit-form" to the desired form and another class to the submit button "disable-mult-click". You can aslo add a font awesome spinner like
<i class="spinner hidden fa fa-spinner fa-spin" style="margin-right: 2px"></i>
Now pest the code below inside script tag. you are good to go.
$('.prevent-mult-submit-form').on('submit', function(){
$('.disable-mult-click').attr('disabled', true)
$('.spinner').removeClass('hidden')
})
Submit the form with AJAX, and the GIF will animate.

Categories