Avoid form multiple submissions and re-enable when done - javascript

I have a form which allows to view data in a page or download it in csv according to the submit button pressed.
Since it's a long database query I want to avoid the user to submit more than once (you know how heavy is users' index finger on left mouse button...) to avoid database overload and also to make user more relaxed...
I wrote this little jQuery code to substitute submit button(s) with a Processing, please wait and the classic animated spinning gif
$(document).ready(function(){
//preload wait img
var $waitImg = $('<img />').attr('src', '/img/wait.gif')
$('.wait').click(function(){
$(':submit').hide();
$(this).after($('<span>Processing, please wait...</span>').prepend($waitImg));
});
});
All works but has some drawbacks:
when user sees results and then press the browser's back button he will get again the Processing, please wait sentence and no submit buttons (what if he just wants to edit something and make a new query)
after user is prompted to download the CSV file he keeps on being told to wait...
Solutions could be to detect someway user is back or download stared or another way to tell him work is in progress.
The easier, the better.

When user sees results and then press the browser's back button he will get again the Processing, please wait sentence and no submit buttons (what if he just wants to edit something and make a new query)
The browser is caching the page. You could try resetting the values/removing the loading image in $(document).ready() which should fire when the user presses the back button using the onunload trick: Is there a cross-browser onload event when clicking the back button?
after user is prompted to download the CSV file he keeps on being told to wait...
It won't be possible to detect this without the help of the server. The easiest thing to do would be to "ping" the server via ajax and the server will tell the client if the download was initiated/sent to the user. This can be done by repeatability calling the server every i.e. 3 seconds to see if the download was initiated and if so, reset/hide the loading image and text.
You could use jQuery deferred to help make this easy and of a nice syntax.
jQuery
function downloadStarted()
{
var $def = $.Deferred();
var check = function() {
$.get('/ajax/check-download-status', function(response) {
if (response.started)
{
$def.resolve();
}
else
{
//Check again in 3 seconds
setTimeout(check, 3000);
}
}, 'json');
};
check();
return $def.promise();
}
Usage:
var success = function() { /* reset/hide loading image */ }
$.when(downloadStarted()).then(success);
PHP/Server side
On the server side ajax/check-download-status will look like so:
session_start();
$json['started'] = 0;
if ($_SESSION['download_started']) $json['started'] = 1;
return json_encode($json);
And obviously when your csv file is sent to the client, set $_SESSION['download_started'] to 1.

Found this:
Detecting the File Download Dialog In the Browser
and this is my code based on it:
html
<form ...>
<fieldset>
...
<div>
<input class="wait" id="submit" name="submit" type="submit" value="View" />
<input class="wait" id="submit" name="submit" type="submit" value="Download as CSV" />
</div>
</fieldset>
</form>
javascript
$(document).ready(function(){
var cookieCheckTimer;
var cookieName = 'download_token';
var $wait = $('.wait');
var $waitMsg = $('<span>Processing, please wait...</span>').prepend(
$('<img />').attr('src', '/img/wait.gif').css({
'vertical-align': 'middle',
'margin-right': '1em'
}));
//add hidden field to forms with .wait submit
$wait.parent().each(function(){
$(this).append($('<input />').attr({
'type': 'hidden',
'name': cookieName,
'id': cookieName
}));
});
$wait.click(function(){
var token = new Date().getTime();
//set token value
$('#' + cookieName).val(token);
//hide submit buttons
$(':submit').hide();
//append wait msg
$(this).after($waitMsg);
cookieCheckTimer = window.setInterval(function () {
if ($.cookie(cookieName) == token){
//clear timer
window.clearInterval(cookieCheckTimer);
//clear cookie value
$.cookie(cookieName, null);
//detach wait msg
$waitMsg.detach();
//show again submit buttons
$(':submit').show();
}
}, 1000);
});
});
Server side if a download_token key is found in request parameters a cookie with its name and value is set.
Here's my python (pylons) code for a controller's __before__ :
python
cookieName = 'download_token'
#set file download coockie if asked
if cookieName in request.params:
response.set_cookie(cookieName,
#str: see http://groups.google.com/group/pylons-discuss/browse_thread/thread/7d42f3b28bc6f447
str(request.params.get(self._downloadTokenName)),
expires=datetime.now() + timedelta(minutes=15))
I set cookie expire time to 15 minutes to not fill up client cookies, you choose an appropriate duration based on time needed by task.
This also will work with browser back button issue as when going back the cookie will be found and buttons restored.

Related

Submit form and refresh DIV without page refresh not working?

Please note this is not a duplicate question. This question involves submitting a form and refreshing a div on a change event - not a click event. FYI.
I have a form to allow users to upload an image. I have removed the submit button and added a javascript on change event to submit the form automatically when the user inputs an image.
This works fine and the image is uploaded.
However, I am also pulling through the image to display this to the user. At the moment, the user does not see the image change until they refresh the page or sometimes not even until they clear their cache.
The div containing the images should refresh upon the form being submitted, and the page itself should not refresh. At the moment the div is not refreshing and I think the form is submitting and refreshing the page.
Please can someone show me where I am going wrong? Thanks
Code:
<!-- Commence Photo Upload A -->
<?php
if(isset($_FILES['image6'])){
$dir = $image .'/F/';
$file_name = $_FILES['image6']['name'];
$file_name = $dir. 'sub_img.jpg';
$file_size = $_FILES['image6']['size'];
$file_tmp = $_FILES['image6']['tmp_name'];
$file_type = $_FILES['image6']['type'];
$tmp = explode('.',$_FILES['image6']['name']);
$file_ext=strtolower(end($tmp));
$extensions= array("jpeg","jpg","png","gif");
if(in_array($file_ext,$extensions)=== false){
$errors[]="extension not allowed, please choose a GIF, JPEG or PNG file.";
}
if($file_size > 2097152) {
$errors[]='File size must be excately 2 MB';
}
if(empty($errors)==true) {
move_uploaded_file($file_tmp, $file_name);
}else{
}} ?>
<script>
$('#uploads6').submit(function(){
var data = $(this).serialize();
$.ajax({
url: "upload_6.php",
type: "POST",
data: data,
success: function( data )
{
//here is the code I want to refresh the div(#container)
$('.image6').html(data);
},
error: function(){
alert('ERROR');
}
});
return false;
});
</script>
<form id="uploads6" action = "" method = "POST" enctype = "multipart/form-data">
<label class="profile_gallery_image_in"><input type="file" name="image6" id="image6" onchange="form.submit()"/><p class="label"></p><img class="myImg" src="<?php echo $image.'/F/sub_img.jpg'; ?>" height="100%" width="100%" /></label>
</form>
For image caching you can try the age old "cachebuster" method.
All it is is put something unique into the url query.
www.example.com/image.jpg?cachebuster=somethingunique
The browser will see this as a new request because it doesn't know what the query string does, it could be a search form for all it cares. So it will not pull it from the cache.
Good choices for the something unque is any time based component, as you know its never been used before. Ive used filesize($file) before when doing image edits.
$url = "www.example.com/image.jpg?cachebuster=".microtime(true); //as a float
$url = "www.example.com/image.jpg?cachebuster=".time(); // only 1 second granularity
$url = "www.example.com/image.jpg?cachebuster=".filesize($file); // based on the size of the file
$url = "www.example.com/image.jpg?cachebuster=".hash_file($file); //based on file contents
And so on. You can even do it in JavaScript if you want to.
For the form
$('#uploads6').submit(function(e){
e.preventDefault();
//.. other code
return false;
});
One note is using $.post how you are will probably prevent the file from being uploaded.
Here is another SO question on that:
jQuery Ajax File Upload
If you want a non-javascript way to upload without refreshing page, you can also do it though an iframe but the onLoad even may not work in Chrome for that, so it can be hard to tell when the file is uploaded from the client side.
Here is a SO question I answered on that back in 2014
How can I upload files asynchronously?
To prevant default form submission try:
e.preventDefault();
To stop event bubling try:
e.stopPropagation();
Also try to add a ‚#‘ or ‚javascript:void(0)‘ in your HTML action-attribute.
You need to use
$('#uploads6').submit(function(e) {
e.preventDefault();
// your code
}
to prevent the submit event from directing to the page that is given in the action value. This is right now the same page since the value of the action attribute is an empty string and therefor the page is refreshed.

Loading screen while Servlet loads

I have this JSP where I select certain parameters and hit "submit" button, after clicking "submit" I am calling a JavaScript function as below
<body>
<input type=button class="button" id = "submit" value="Evaluate"
onclick="JavaScript:return evaluateFunction()">
</body>
and in the evaluateFunction() I am collecting all the parameters and call a new Servlet in new popup window as below:
<script>
function evaluateFunction(){
var win = window.open('ConfirmEvaluate?parameters,'mywindow','width=600,height=500,titlebar=no')
}
</script>
Now the issue is ConfirmEvaluate servlet takes some time to get the data from database(around 15-20 secs based on size of input) and displays the data in the forwarded JSP(say userdata.jsp)
Now I want to display a loading gif or screen in that 15-20 seconds while the Servlet loads the data from database.
How can I proceed, any help would be appreciated.
I have already gone through some similar questions in SO but none of them is having a specific answer.
You have to use AJAX. Servlet requests like the one in your example are synchronous. Which means it will wait until the processing finishes then do the next activity.
With an AJAX request you can send the request and then do something else without having to wait for it to finish processing, because it is asynchronous.
The way i would approach this is in the following way:
You get the user details in ConfirmEvaluate, and redirect the user to userdata, then once the user is on the page do the AJAX request to fetch the information that takes a long time to process. When the request is made you can show a loading icon but when you get a response from the AJAX request, you can hide this loading icon. Check out this brilliant post on how to make AJAX requests with servlets
I had to implement something like this recently, here is some example code:
<script>
//when page loads, the ajax request starts
$(document).ready(function() {
$(this).scrollTop(0);
getposts(username);
});
//ajax request that will show and hide the loader depending on response
var getposts = function (username) {
var params = {
user: username
};
$.get("../GetUserFeed",$.param(params),function(responseXml) {
$("#user-feed").append($(responseXml).find("feed").html()); // Parse XML, find <data> element and append its HTML to HTML DOM element with ID "somediv".
$('#logo-loader').hide();
if(isBlank(responseXml)){
$('#logo-loader-completed').show();
$('#logo-loader-image').hide();
}
});
};
</script>

How to tell if ajax request was cancelled by form submission?

I've added ajax calls that fire when a user leaves a text box to automatically save their text. There is also a save button at the bottom of the page (the save button is still necessary because it permanently archives the document state at that point in time).
The problem is when a user edits a text box and then directly clicks the submit button. The ajax request is made but then the submit request kills it and I get an error. If I don't get a successful response back from the server then I display a message letting the user know there is a problem (long story short, we've had issues with users spending a long time entering data and then for whatever reason it doesn't get submitted and they lose it all).
In the case that they hit the Save button, I don't care that the request is cancelled because the hitting Save is, obviously, going to Save the data anyway. How can I differentiate between an ajax error where connectivity was lost versus one where it was cancelled because the form was submitted?
I tried this:
var formIsSubmitting = false;
$(document).ready(function () {
$('form').on('submit', function (e) {
debugger;
formIsSubmitting = true;
});
});
function handleError(xmlRequest) {
debugger;
if (!formIsSubmitting)
alert(xmlRequest.status + ' \n\r ' + xmlRequest.statusText + '\n\r' + xmlRequest.responseText);
}
This didn't work though. Also it doesn't break on either of the debugger lines so not sure what's up with that either.
EDIT:
Here's what the button looks like:
<asp:LinkButton ID="lbnSaveP1" runat="server" OnCommand="GoToPage"
OnClientClick="return validateP1();" CommandName="1" CommandArgument="1" />
validateP1 doesn't do anything fancy... just what you'd expect.

Allow Save new item and continue in SharePoint NewForm.aspx

Short : How to make a default SharePoint NewForm.aspx add an item and stay on the input page instead of returning to the list view AllItems?
long :
I am asked to allow SharePoint users to enter many new items to a SharePoint list without having to return to AllItems each time they save.
This requirement applies to many lists so I don't want to develop specific code for every possible content type.
I though I could write a short js file and use it whenever the the user wants to save and continue.
So far I tried to add the "Save and continue" behavior in a Content Editor Web Part (CEWP).
My first approach was to change the Source= parameter with no success (either cancel returned also to the new source or the source was ignored when set in preSaveAction().
Then I tried to set the form action in preSaveAction :
<script type="text/javascript">
JSRequest.EnsureSetup();
var src = JSRequest.QueryString["Source"];
var exit = JSRequest.QueryString["exit"];
var isDialog = JSRequest.QueryString["IsDlg"];
var dlgParam = "";
if (isDialog)
dlgParam = "&IsDlg="+isDialog;
//If exit is defined its keeping default source parameter
if (exit) {
document.forms.aspnetForm.action= location.pathname+"?Source="+exit+dlgParam;
}
function PreSaveAction(){
//before saving the original source is saved in exit
exit=JSRequest.QueryString["Source"];
src=escapeProperly(window.location.protocol + '//' + window.location.host + _spPageContextInfo.serverRequestPath);
document.forms.aspnetForm.action=location.pathname+"?Source="+src+"&exit="+exit+dlgParam;
return true;
The action is updated as expected but the user is still redirected to AllItems.aspx when a new item is saved.
Another attempt was to add a specific button reusing the SharePoint javascript action used in the ribbon and page buttons
<script type="text/javascript">
function adressePage() {
return window.location.protocol + '//' + window.location.host + _spPageContextInfo.serverRequestPath;
}
function saveContinue() {
document.getElementById("cmdSaveContinue").disabled=true;
if (!PreSaveItem()) return false;
if (SPClientForms.ClientFormManager.SubmitClientForm("WPQ2")) {
SP.UI.Notify.addNotification("Saving ...", false);
window.location = adressePage();
} else {
WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("cmdSaveContinue", "", true, "", adressePage(), false, true));
}
document.getElementById("cmdSaveContinue").disabled=false;
}
</script>
<input id="cmdSaveContinue" onclick="javascript:return saveContinue();" type="button" value="Enregistrer et continuer" style="top: -5.5em; position: relative;"/>
This way, form validation is processed and the item is saved.
If error messages are returned, the form stays on NewItem but the error messages are lost after the window.location=... is executed.
When everything works well, the item is saved and the user is on a new empty NewForm.aspx.
But SharePoint SPClientForms.ClientFormManager.SubmitClientForm("WPQ2") is executed asynchronously and sometimes (not always) the redirection to
AllItems occurs after the end of my redirection.
I am stuck at this point and fear to be forced to edit each and every NewForm page in SPDesigner whenever a list is added...
Infos : SharePoint server 2013 on premise, SPDesigner possible
You can do this through InfoPath, which you should be able to use if you have SP on prem and SPDesigner access. If you go to InfoPath and customize the form, you can go to Data > Submit Options > (advanced >>) > After Submit > New Form.
You can either google 'InfoPath Save and New' or go to the Microsoft site and check out this walkthrough. Their walkthrough suggests using two buttons, one of which opens a new form and the other which closes the form.
Create a custom NewForm.aspx and add a new button and mention {} in redirect.
<input type="button" class="contact-button" value="Submit and Create New Request" name="btnSaven" onclick="javascript: {ddwrt:GenFireServerEvent('__commit;__redirect={}')}" />
add script editor web part to a view
<input type="button" value="Add items in continuity" onclick="openNewItemDialog()"/>
<script>
function openNewItemDialog() {
var options = {
url: 'http://sp/sites/dev/Lists/<yourList>/NewForm.aspx',
dialogReturnValueCallback: function(result, returnValue) {
if(result== SP.UI.DialogResult.OK)
{
openNewItemDialog()
}
}
}
SP.UI.ModalDialog.showModalDialog(options);
}

Greasemonkey doesn't execute again after form prints result

I'm using greasemonkey to manipulate a form on an existing web page. (autofill)
The action attribute of the form is itself, once submitted it prints a success message above the submit button.
What I'm trying to do is, once the form is submitted - I want to redirect the browser to another page. But this doesnt work with greasemonkey. Nothing happens.
I wrote a code to detect when the page is submitted, but doesnt work after the form is submitted.
getData("goingback"); //pulls the goingback data from database using ajax
if (goingback == "yes") {
window.location = "index.php";
} else {
//business as usual
// manipulate the form and get it ready for submission
sendPost("goback","yes"); // this function sends data to a php to be handled via ajax
//ajax stores the data in database
//the form is submitted using a timer and .click();
var submission = Math.floor(Math.random() * 10000) + 5000;
setTimeout(function() {
$('button[value="submit"]:first').click();
}, submission);
}
How can I achieve this?
Thanks in advance
The question is not clear; we might need to see the actual page itself. But, it sounds like the page is submitting the form via AJAX, and not a full post.
In that case, your script won't refire. Instead, monitor the page for the success message. Here's one way:
Suppose the success message is like this:
<div id="post_status">
<h2>Some one set us up the (data) bomb!</h2>
</div>
where the <h2> is added after the form posts.
Then this code will redirect after the post happens:
var postChkTimer = setInterval (checkForPostDoneNode, 200);
function checkForPostDoneNode () {
var postDoneNode = $("#post_status h2");
if (postDoneNode.length) {
window.location.assign ("index.php");
}
}
There is no need for that getData("goingback") or
sendPost("goback","yes"). Also that looks like it's setting goback but checking goingback -- which could be a problem. Although it is not the problem causing the behavior as described in the question.

Categories