I have written an AJAX script that saves form data and then displays a preview page of this data all in one click event. Here is the script:
$('#ajax-preview').click(function(e) {
var formData = $('#advertiser-edit-form').serializeArray();
$.ajax({
type: 'post' ,
url: "ajax-preview.php",
data: formData,
success: function(data, status, jqXHR) {
previewURL = data;
$('#ajax-preview').attr('href', previewURL);
}
});
});
The problem is that sometimes the PHP script does not manage to complete its saving routine before a user is taken to the preview page. In such case, the user would see unupdated data when he's taken to the preview page. Then he would have to reload the page to see the changes.
How can I design the script so that a user is taken to the previewURL only after the AJAX updated the data?
The problem is that the code in your click handler only starts the ajax call, it doesn't wait for it to complete, and so the click's default behavior (following the link) occurs immediately, while the ajax call is still running. You can't make the click event wait unless you want to make the ajax call synchronous, which makes for a poor UX.
Instead, I suggest having a button the user presses to generate the preview, which makes the ajax call, and then have the ajax result reveal (unhide) a link the user can click to see the preview.
Rough example:
$("#btn-create-preview").click(function() {
var pending = $("#preview-pending"),
msg = $("#preview-message"),
btn = this;
btn.disabled = true;
msg.hide();
pending.fadeIn("fast");
// Simulate ajax via setTimeout
setTimeout(function() {
// This is the ajax completion function
pending.hide();
msg.find("a").attr(
"href",
"http://example.com?x=" + Math.floor(Math.random() * 10000)
);
msg.fadeIn("fast");
btn.disabled = false;
}, 1000);
});
<input type="button" id="btn-create-preview" value="Create Preview">
<em id="preview-pending" style="display: none">
Building your preview...
</em>
<span id="preview-message" style="display: none">
Your preview is ready;
click here
to view it.
</span>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Related
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>
I have a "Save" button that I need to trigger when the user clicks Next/Previous buttons on my page. When the user clicks next to move onto another window I trigger a "save" button that saves the changed the user had mad and some other functionality. The problem is when I click the next or previous button the save button is triggered but needs time to save the changes and the code keeps on executing. Is there a way I can tell whether the save has finished or delay my code somehow? I know I can do a time delay but it could be different for every user and inefficient. Here is an example:
function prev_next(){
$('#save').trigger('click'); //This line could take 2-5 seconds to finish
//Other code here that opens next window
}
Any advice will be appreciated.
You will have to edit the function that gets triggered by clicking the save button, to allow for a callback function. (I assume there is an ajax request that is sent to some server to save).
Example:
Save function:
function saveEdits(callback){
$.ajax({
url: 'urltosavepage.php',
method: 'post',
data: {
somevar: 'somevalue'
},
success: function(response)
{
callback();
}
});
}
prev_next function:
function prev_next()
{
saveEdits(function(){
// Code that is here will not get executed until after the ajax request is completed, and the success function gets called.
//Other code here that opens next window
});
}
I have a page that lets you Add/Edit/Delete "Project Tasks" and Save the data to a database using jQuery's AJAX function to save the POST data.
I currently have 2 buttons on the page.
Button 1 .save-tasks-ajax-redirect - You click it and it makes a regular non-ajax POST to my backend and you are redirected to another Project page. This button does not have a click event yet. Perhaps the best way might be to simply create a new click event for this button class and then have it call my save function but it could pass in a variable to indicate that it needs to redirect? Before I posted this questions I was sort of hoping to have both button share the same click event and everything but perhaps this is a better idea?
Button 2 .save-tasks-ajax - You click it and it uses AJAX to Save the data and you can remain on the page editing more.
Now my goal is to modify how Button 1 works. Instead of making a regular HTTP POST, I would like for it to also make an AJAX save but when it is done, I would like it to redirect to a project page.
So below I have my 2 button HTML codes. Below that I have my jQuery Click event for my AJAX save button (Button 2) and below that I have my ajaxSaveTasks() function that my button calls to make the save.
I would like to modify this function and perhaps all of this code so that my Button 1 can use the same function to make an AJAX save but somehow it needs to differentiate itself so that it can also do a redirect after the AJAX save is complete.
Looking at the basic code below, how could I modify this to do that?
<button type="submit" class="save-tasks-ajax-redirect">Save Tasks and Return to Project</button>
<button type="submit" class="save-tasks-ajax">Save Tasks and Continue Editing</button>
$(window).load(function () {
// AJAX Save and Continue editing
$('#content').on('click', '.save-tasks-ajax', function () {
console.log('AJAX Save and Continue Editing Button Clicked!');
ajaxSaveTasks();
return false; // avoid to execute the actual submit of the form.
});
});
function ajaxSaveTasks(){
console.log('ajaxSaveChanges() Ran and Tasks Saved.');
// Reset Flag that Triggers Un-Saved Alert on page exit
window.unsavedChanges = false;
// Show a Loading/Saving Spinner
jQuery('#project_tasks').showLoading();
// Display a message to the user that we are Saving
flipNotify.show({
message: 'Project Tasks Saved!',
icon: 'tick',
delay: 2,
sticky: false
});
var url = "index.php?module=apoll_Web_Projects";
$.ajax({
type: "POST",
url: url,
data: $("#editTasksForm").serialize(), // serializes the form's elements.
success: function(data)
{
// Hide Header Un-Saved Changes Div
hideTaskUnSavedChangesHeaderBar()
// Hide Loading/Saving Spinner
jQuery('#project_tasks').hideLoading();
}
});
};
$(window).load(function () {
// AJAX Save and Continue editing
$('#content').on('click', '.save-tasks-ajax', function () {
console.log('AJAX Save and Continue Editing Button Clicked!');
ajaxSaveTasks();
return false; // avoid to execute the actual submit of the form.
});
// AJAX Save and redirect
$('#content').on('click', '.save-tasks-ajax-redirect', function () {
console.log('AJAX Save and Redirect Button Clicked!');
ajaxSaveTasks(function(){ window.location.assign("project.php"); });
return false; // avoid to execute the actual submit of the form.
});
});
function ajaxSaveTasks(callback){
... your code ...
$.ajax({
...
success: function(data)
{
// Hide Header Un-Saved Changes Div
hideTaskUnSavedChangesHeaderBar()
// Hide Loading/Saving Spinner
jQuery('#project_tasks').hideLoading();
if (callback)
callback();
}
});
};
I m loading some content using ajax call, Inside that contents there are some hyperlinks which when user clicks it loads the content in the same div the problem is when the user clicks the back botton(another ajax call) the content of the div is repalced with the old content(having hyperlinks) ,now when u again click the Hyperlink its functions smoothly but its goes to the action twice, and this phenomenon keeps on increasing the no of time u press the back button and click on some Hyperlink.
Please anyone help me know what exactly happening to the process which is causing increment in action call every time the user clicks it
UPDATE
$(document).on("click",".selector",function(){
var link=($(this).parent().find("td a").attr("href"));
$.ajax({
type : "POST",
async : true,
url : link,
statusCode : {
404 : function() {
alert("Error in Application");
}
},
cache : false,
success : function(data) {
alert(data);
$('#load').html('');
$('#load').html(data);
}
});
});
Try with Call event.stopPropagation(); after successfull ajax request
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.