Hidden iFrame file upload submits an extra time on each subsequent submit - javascript

I'm trying to create a simple file upload form for my website. I'm using a hidden iFrame to do it "ajax" style so I can have a user upload files one after another using the same form.
Right now I have a form with an <input type="file" />. What I have happening is when the input field changes(user selects a file) it should submit the form with the target set to the iFrame which loads a php script and then reset the input field to allow the user to upload again. What seems to happen is the form gets submitted based on the amount of times the form was submitted. e.g if you press the button when the page loads it will submit one time, however if you press the button again(without reloading the page) it will submit two times, and when you press the button for a third time it will submit the form three times and so on.
Here is my javascript for when the input changes
newupload is the id of the input
newimgform is the id of the form
postframe is the id of the iframe
$("#newupload").change(function() {
var max = 5242880, iframe = $("#postframe"), iframeContents;
$('#newimgform').attr("action", "uploadPicture.php")
$('#newimgform').attr("method", "post")
$('#newimgform').attr("MAX_FILE_SIZE", max)
$('#newimgform').attr("enctype", "multipart/form-data")
$('#newimgform').attr("encoding", "multipart/form-data")
$('#newimgform').attr("target", "postframe")
$('#newimgform').submit();
$("#postframe").load(function() {
iframeContents = jQuery.parseJSON($(this.contentDocument).find('body').html());
alert(iframeContents.filename);
$("#newimgform")[0].reset();
});
});
I looked for anyone else trying this and I've seen some answers on here that talk about the submit is being bound multiple times and I need to use unbind like $('#newimgform').unbind("submit").submit(); but that doesn't seem to do anything. I can't use any flash uploaders or anything so this has to be pure html/javascript/php.

You can move out the iframe load handler because it need not be added every time you upload a file. And also you can optimize your code like this.
$("#newupload").change(function() {
$('#newimgform').attr({
action: "uploadPicture.php",
method: "post",
MAX_FILE_SIZE: 5242880,
enctype: "multipart/form-data",
encoding: "multipart/form-data",
target: "postframe",
}).submit();
});
$("#postframe").load(function() {
var iframeContents = jQuery.parseJSON($(this.contentDocument).find('body').html());
alert(iframeContents.filename);
$("#newimgform")[0].reset();
});

Bind the load event handler outside the change event handler. As it is, everytime you change the value of #newupload, a new event handler is bound to the #postframe element:
$("#postframe").load(function() {
var iframeContents = jQuery.parseJSON($(this.contentDocument).find('body').html());
alert(iframeContents.filename);
$("#newimgform")[0].reset();
});
$("#newupload").change(function() {
$(this).attr("action", "uploadPicture.php")
.attr("method", "post")
.attr("MAX_FILE_SIZE", 5242880)
.attr("enctype", "multipart/form-data")
.attr("encoding", "multipart/form-data")
.attr("target", "postframe")
.submit();
});
You could alternatively unbind the load event handler each time it runs, but this seems unnecessary in your case. $(this).unbind('load'); is all you would have to add to the load event handler.
Also you can optimize this, a lot. You are using the same selector over and over, when in jQuery we chain function calls.

Related

Is it correct to put an event inside an event?

I have an script in which I'm going to add a file XLS, once that I validate the file format, I close a bootstrap's modal and open another modal which is an confirmation window to see whether the user is sure to upload that file.
This confirmation window has a confirmation button, once clicked I want that execute me an function which it's going to run an AJAX to make the request to the server.
However, because of that, I had the following doubts:
Which of the 2 ways is better (and the most correct) to run the code and why?
Why is the click event of the first input file executed if there has not been an event change? I mean, I add a file and the event change is executed and I can make clicks many times as I want, is not it supposed that I must add another file so that I can run the function inside again?
Put an event inside an event, has it a name?
$(document).ready(function(){
//First input file
$(document).on('change','#file', function(){
let file = $(this);
let nameFile = file[0].files[0].name;
let button = '<button type="button">Clic input 1</button>';
$('#button').html(button);
$('#button').click(function(){
console.log('CLICK IN FIRST INPUT FILE!');
});
});
//Second input file
$(document).on('change','#file2', function(){
let file = $(this);
let nameFile = file[0].files[0].name;
let button = '<button type="button">Clic input 2</button>';
$('#button2').html(button);
});
$('#button2').click(function(){
console.log('CLICK IN SECOND INPUT FILE!');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" id="file" name="file" />
<div id="button"></div>
<div style="margin-top:20px"></div>
<input type="file" id="file2" name="file2"/>
<div id="button2"></div>
Put an event inside an event, has it a name?
It has, the name is Bad Idea. Let me Expain. What happens when you execute the following code.
$('#button').click(function(){
console.log('CLICK IN FIRST INPUT FILE!');
});
A click event is registered to the button. Once an event is registered, it will fire everytime no matter how many times you click.
When you put that code inside another event handler like the first example, it gets executed everytime the file-input changes and a new event handler is registered. So when you select a file, and then decide to change it, file-input changes twice and you get 2 click events registered. Now click on the button, you get 2 new console log printed by one click!!! Try it..
Why is the click event of the first input file executed if there has
not been an event change
Because that's how event handler works, you register once, they get fired everytime after that.
Which of the 2 ways is better (and the most correct) to run the code
and why?
Obviously not the first one, because it is a bad idea, Not the second one either. In case of second one you are attaching event to a division that will contain the button. So you don't need to click on the button, just click anywhere right side of the button, the event gets fired!!!
So if none of them is right, what can we do?
Do not generate button/any html element by javascript for such simple tasks. Do it with HTML, plain and simple.
Do not nest event handler into another i.e put one event handler inside another, it will complicate things. Just put all event handlers directly inside document.ready event of jQuery. document.ready only fires once.
When you need to control user action then show/hide your button or other html element by javascript based on required conditions.
My suggestion is doing something like this.
$(document).ready(function(){
// Hide the button at first
$('#button').hide();
// When File-input changes
$('#file').change(function(){
if(**the file-input has a file selected**){
$('#button').show();
}
else{
$('#button').hide();
}
});
// When Button Clicked
$('#button').click(function(){
// Do the action
});
});
Which of the 2 ways is better (and the most correct) to run the code and why?
I believe this is better:
//Second input file
$(document).on('change','#file2', function(){
let file = $(this);
let nameFile = file[0].files[0].name;
let button = '<button type="button">Clic input 2</button>';
$('#button2').html(button);
});
$('#button2').click(function(){
console.log('CLICK IN SECOND INPUT FILE!');
});
Mainly because it's more readable and easy to follow. There is no need to have the button click event set up AFTER the input has been changed. It is better to change the STATE of the button, as you are doing. Even better would be to hide/show the button like:
$('#button2').show();
And have it initially hidden with:
<div id="button2" style="display: none">Click me</div>
Why is the click event of the first input file executed if there has not been an event change?
In my test, this all worked correctly.
How is called this?
The change events should only be called when you click and assign a file to the input.
you are binding the same event multiple times to the same button object. binding the same event to the same object in another event that may reoccur will result in binding it over and over (stacks events and fire them and in this case "it" multiple times). binding an action to an event should happen only one time per object. and I see that you are binding the click event to the div instead of the button. maybe you need to consider dynamic binding using .on() like this
$(document).ready(function(){
//first file change event
$(document).on('change','#file', function(){
let file = $(this);
//handling empty selection
if(file[0].files.length == 0){
$('#button').html("");
return;
}
let nameFile = file[0].files[0].name;
let button = '<button type="button">Clic input 1</button>';
$('#button').html(button);
});
//second file change event
$(document).on('change','#file2', function(){
let file = $(this);
//handling empty selection
if(file[0].files.length == 0){
$('#button2').html("");
return;
}
let nameFile = file[0].files[0].name;
let button = '<button type="button">Clic input 2</button>';
$('#button2').html(button);
});
//first button dynamic event (doesn't stack)
$('#button').on('click','button', function(){
console.log('CLICK IN FIRST INPUT FILE!');
});
//second button dynamic event (doesn't stack)
$('#button2').on('click','button', function(){
console.log('CLICK IN SECOND INPUT FILE!');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" id="file" name="file" />
<div id="button"></div>
<div style="margin-top:20px"></div>
<input type="file" id="file2" name="file2"/>
<div id="button2"></div>
note that you need to handle not choosing a file (e.g. files count is 0) like in my code
Put an event inside an event, has it a name?
It does have a name. It's called "daisy chaining" and it's not a good idea.
not enough rep to comment
I've had cause to do this. I had the unpleasant task of mucking through 2 years of code written by one person with little maintenance or code discipline. I wanted to keep the code structure intact, so I daisy-chained click events to perform some enhancements.
To avoid some problems mentioned in the better answers above, simply remember to call $(selector).off("click") before binding the next event.
const mainevent = (e)=>{
e.preventDefault();
your event data
.then((e) => {
second event()
})
.catch((error) =>
alert(error.message))
};
}

How to set Autoclick on all the buttons of a page?

I am using Jquery and Ajax for performing the action, I need after loading complete page, a code click on the every button automatically.
I used the following javascript code for click all the buttons in the end of my page. but it is not working.
<script type='text/javascript'>
document.getElementByClassName('sub').click();
</script>
Structure of my Page code
[JQuery]
[PHP]
[HTML]
[Javascript]
I set all the buttons type as "BUTTON", When I set
type="submit"
The Autoclick code only work on the first button, but with the "button" type it is not working with any of them.
If I click manually on that buttons they are working properly.
Please give any suggestion. Thank You.
Youre using the wrong function. Elements is plural in that method.
document.getElementsByClassName('sub');
Additionally, calling click on this NodeList will not work. You need to loop through and call the event on each index.
Also, you say you're using jQuery. To ensure your call happens after DOM ready, wrap your JS with $().ready().
Last, use the tools you've provided yourself, in this case jQuery, and select your element that way.
$(document).ready(function(){
$(".sub").click()
});
In jQuery you can trigger the click like
$( ".sub" ).trigger( "click" );
Because you retrieve a NodeList(as pointed out in the comments) :
$(document).ready(function () {
var butEl = document.getElementsByClassName('sub'),
count = butEl.length;
for (i = 0; i < count; i++){
butEl[i].click();
}
});
Also is getElementsByClassName
If you're trying to click on multiple different form submit buttons, it makes sense that the browser will POST for only one of them - one page can't simultaneously navigate to multiple different URLs.
Similarly, when you change type to button, none of the forms will be submitted, even though you're clicking on the buttons.
If you know what you're doing, you could always add submit event handlers to all of your forms, and submit them via ajax requests instead - which should allow multiple of them to be processed. Note you may need to work out some extra logic for displaying success/failure for each form to the user since the browser won't navigate you to any of the existing "submitted" pages.
$(document).on('submit', 'form', function() {
$.ajax({
url: $(this).attr('action'),
type: $(this).attr('method'),
dataType: 'json',
data: $(this).serialize(),
success: function(data) {
// Add logic here for handling success for each form, if required
},
error: function(xhr, err) {
// Add logic here for handling errors for each form, if required
}
});
return false; // To stop the browser processing this form
});
With this method, your first attempt with type="submit" buttons should work - however I would encourage you to be as specific as possible with your element selectors for both the forms and the buttons you're trying to target.

jQuery disable double click prevention breaking functionality of a PHP function in a form

I have a jquery bug that I cant solve - hoping for help with a solution. Dont know if it is browser bug related (probably not), jQuery related, or Yii (our backend) related - but I need to try to solve it with the jQuery portion. Code at bottom of message.
Requirement: Disable accidental double submissions on forms.
Current Solution: Check for form submission state through a delegate and when the DOM form state changes to submit - append the disable attribute to the form submit button to prevent accident double form submission.
jQuery double click disabler:
$( document ).ready(function() {
$('html').delegate('form', 'submit', function() {
$(this).find(':submit').attr('disabled', true);
});
});
Problem: This works perfectly on every part of the CRM we are developing EXCEPT for a single timekeeper (clock in/clock out) feature. With the timekeeper the form has two submit buttons (one for clock in, one for clock out). Only one submit button shows at a time (Either "In" or "Out". When you click the button - it submits the form and changes the submit button to the other state by checking a session var to determine what state it is in and determines which of the two submit buttons are to be displayed. Problem is if you click it, the form appears to submit, but the state don't change. If you click it really fast a few times you can get it to change state. I suspect this is a timing or order of operations issue, but I have no idea how to fix it. The fix MUST be done on the front end, so here is the code (both the PHP being impacted and jQuery double click prevention). Perhaps a different method of disabling double submissions may work, please post your solution if you have one to try. Commenting out the current jQuery allows the form to function as designed. What might be causing this, and how might I change the jQuery double click prevention to solve it?
On page PHP for the time clock:
<form action = "<?=$clockUrl?>" method = "post" >
<input type = "hidden" name = "previousUrl" value = "<?=$currentUrl?>">
<?php if ($sessionVar->timeclockin) {?>
<input type = "submit" name = "submit-clockout" value = "Out">
<class="clock-time" ><?=$sessionVar->timeclockin?></class="clock-time">
<?php } else {?>
<input type = "submit" name = "submit-clockin" value = "In">
<?php }?>
</form>
Thank you for pointing me in the right direction Tyler! I was able to fix the issue with the following alteration to my script.
function do_nothing() {
console.log("click prevented");
return false;
}
$('html').delegate('form', 'submit', function(e) {
$(e.target).find(':submit').click(do_nothing);
setTimeout(function(){
$(e.target).unbind('click', do_nothing);
}, 10000);
});
Update 1:
If you are looking to prevent the button from being pressed twice then inside of your onclick or submit function, you should use something similar to the following:
$('#yourButton').prop('disabled', true);
If the page then redirects then you won't have to undo this. If it does, then do the opposite by changing true to false.
The submit function should instead disable the submit button until it either returns or fails.
An alternative is to use a lambda style function and replace it temporarily with an empty function until the request returns or fails.

Aweber form not collecting leads because of simple jquery code [duplicate]

I have a form that uploads a file and targets an iframe on the page. When the user clicks submit, I want the file contents to "clear" out.
I tried this
$('#imageaddform').submit(function(){
$('#imagefile').val('');
});
But it clears the form before the submit, so nothing is ever uploaded.
Is how do I clear after submit?
If you have no other handlers bound, you could do something like this:
$('#imageaddform').submit(function(e) {
e.preventDefault(); // don't submit multiple times
this.submit(); // use the native submit method of the form element
$('#imagefile').val(''); // blank the input
});
Lonesomeday's solution worked for me but for Google Chrome I found it would still submit empty form data unless I added a timeout like this:
$('#imageaddform').submit(function(e) {
e.preventDefault(); // don't submit multiple times
this.submit(); // use the native submit method of the form element
setTimeout(function(){ // Delay for Chrome
$('#imagefile').val(''); // blank the input
}, 100);
});
You could do something like this:
$('#imageaddform').submit(function(){
setTimeout(function() {
$('#imagefile').val('');
},100);
});
How are u submitting the form? if this is normal form post then then page wont exist in that case i am wondering if u are looking to clear the form before the page refreshses so that when the user comes back he doesn't see the values populated.
If the form is submitted by ajax then you can
function(){
$('form1')[0].submit();
clearForm();
}
Did i miss the question?

Prevent submit while jQuery effect is running

I have this issue that when user clicks a button (in this case, a submit button) multiple times, jQuery will keep playing the animation effects until it has completed the count of clicks the user has imputed.
This can get quite overwhelming.
How can jQuery tell if it's currently executing an animation to a particular element, so I can prevent user from submitting while the elements effect is still in play?
Notes: the submit button is in a file. Form handling is relayed via AJAX this jQuery is inside the ajax called file.
Here is the main files code:
$('#login_form').submit(function(e) {
$.post(
"ajax.php",
{ user: $('[name="username"]').val(), pw: $('[name="password"]').val() },
function(resposeText) { $('#login_form_response').html(resposeText); },
"html"
);
e.preventDefault();
});
Here is the code (in ajax'ed' file):
$('#login_form_response').html('Username or Password is inaccurate!')
.slideDown()
.delay(3500)
.slideUp(1500);
You could unbind the event-handler just before starting the animation, and in the callback function of the animation, just bind the handler again.
$('#button').unbind('click');
$('#animated_element').animate({ animation, stuff}, 1000, function(){
$('#button').bind('click', handlerFunc);
});
Note:
This is a way to prevent submitting when you are using a customized button (div, or a link), which has an event handler binded to it. It does not work on pure html <input type="submit" /> - buttons, because after unbinding, the standard-submit is going to take effect.
I prefer to use customized buttons, mainly because of styling (especially for IE7 and such).
If you want to use a pure html-submit button, you'll have to disable the button (and disabling submit over "enter") or set a flag, that prevents submitting, as other users have already stated in their answers!
Disable the submit button until the animation finishes.
$('animatingElementSelector').animate({height: 200px;}, slow, function() { //ENABLE BUTTON HERE });
var isAnimationRunning;
jQuery('#myForm').bind('submit',function(e){
if(isAnimationRunning)
{
e.preventDefault();
}
});
Create a variable isAnimationRunning let it know, animation running or not. If running then ignore submit.
http://jsfiddle.net/praveen_prasad/cfvRf/
On demo click start animation and then try to submit!!
Edit 1
Some ppl have suggested unbinding click of submit button, that wont work. If a submit button is inside a form, clicking it will submit the form, you dont bind click event to submit form, its just pure html, so unbinding wont help in stopping submit event. check this demo
Edit 2
Some ppl have suggested disable the submit button during the animation. That wont always work either, consider a situation where user types something in text box and press enter key, form will be submitted(some browsers will) regardless of submit button being disabled.
Just add disabling button when it clicked :) or hide... or both of this... hide and disable
Try this:
$('#login_form').submit(function(e) {
$('input[type=submit]', this).attr('disabled', 'disabled').attr('style','opacity: 0.5; filter: alpha(opacity = 50); ');
$.post(
"ajax.php",
{ user: $('[name="username"]').val(), pw: $('[name="password"]').val() },
function(resposeText) { $('#login_form_response').html(resposeText); },
"html"
);
e.preventDefault();
});

Categories

Resources