When one ajax is SUCCESS load next - javascript

I have been looking into a jQuery Ajax queue system. I have a step by step generator. It generates a pdf and then once the pdf is generated an image is created. Once these 2 processes are complete I then send an email confirmation. It must also be flexible to add additional steps.
However, I have yet to find an example that works. They all use 'COMPLETE' rather than 'success' so if I return an error via jSON then it is ignored. It moves on to the next in the queue
Any ideas?
EDIT
It's quite complex whats happening.
My plugin (copied from another plugin)
$.AjaxQueue = function() {
this.reqs = [];
this.requesting = false;
};
$.AjaxQueue.prototype = {
add: function(req) {
this.reqs.push(req);
this.next();
},
next: function() {
if (this.reqs.length == 0)
return;
if (this.requesting == true)
return;
var req = this.reqs.splice(0, 1)[0];
var complete = req.complete;
var self = this;
if (req._run)
req._run(req);
req.complete = function() {
if (complete)
complete.apply(this, arguments);
self.requesting = false;
self.next();
}
this.requesting = true;
$.ajax(req);
}
};
I have also written a function to speed my code up
function createQueue(file, inputid, step, params) {
var queue = new $.AjaxQueue();
queue.add({
url: file,
type: 'POST',
dataType: "json",
data: params,
complete : function(data, status) {
$('li#step' + step + ' .loading').remove();
// DO SOMETHING. CANT CHECK FOR ERRORS
},
success : function(data, status) {
// DOES NOT WORK
},
error: function(xhr, desc, err) {
console.log(xhr);
console.log("Details: " + desc + "\nError:" + err);
},
_run: function(req) {
//special pre-processor to alter the request just before it is finally executed in the queue
//req.url = 'changed_url'
$('li#step' + step).append('<span class="loading"></span>');
}
});
}
Step 1. I am using mpdf to generate a pdf. Now this takes a few seconds to actually build depending on theme, images used etc. So i call this:
createQueue('post_pdf.php', id, 1, { 'filename': filename + '.pdf', 'id': id, 'crop': crop } );
Step 2 - Generate some images
createQueue('ajax_image.php', id, 2, { 'filename': filename + '.pdf' } );
Step 3 - (something else like send email summary)
createQueue('mail.php', id, 3, { 'from': 'newfilename', 'to': 'emavle#pb.com', 'subject': 'This is a subject', 'body': 'Body Copy' } );
If it fails at step 1 I can see it in console but its not returned

As #charlietfl suggested, have each step in PHP on server side. After the AJAX call is done, you can have the response from the server and continue based on that. Example:
// make AJAX request to file.php and send 'data'
var request = $.ajax({
url: "file.php",
type: "POST",
data: { data }
});
// when PHP is done, receive the output and act accordingly
request.done(function( msg ) {
if (msg == "A") {
// plan A
} else if (msg == "B") {
// plan B
}
});

Related

Success function not working based on submit

I have a Ajax call that is working, but the success function isn't. I have a a few dates that I am inputting, after hitting submit, there should be a little alert popup saying "Data saved to the DB". The data is getting saved to the DB, however I am not getting the popup alert window.
$("#btnSubmit").bind("click", function () {
createUpdateArrays();
var url = "/Sample/Selection";
$.ajax({
type: "GET",
url: url,
data: { ids: ids, dates: dates },
success: function (success) {
if (success === true) {
alert("Success");
}
else {
alert("error");
}
}
});
ids = "";
dates = "";
});
function createUpdateArrays() {
var i = 0;
$('input.remedy-id:checkbox').each(function () {
if ($(this).is(':checked')) {
var rid = $(this).attr("id");
$('.planned-date').each(function () {
var did = $(this).attr("id");
if (did === rid) {
var date = $(this).val();
ids += rid + ",";
dates += date + ",";
}
});
};
});
};
I can't seem to understand the reason behind this..
EDIT: Before doing ANYTHING else, make sure that your server is actually returning a response to begin with.
Your success function is expecting a boolean to be returned by the server, but this is probably not what is happening. If you're returning a simple string "success" from the server, then the comparison should be if (success === "success"). This is entirely dependent on what your server is returning as a response.
Perhaps your server is returning a status code of 2xx. In either case, you can use the jQuery status code callbacks:
$.ajax({
type: "GET",
url: url,
data: { ids: ids, dates: dates },
statusCode: {
200: function(){alert("Success!")},
201: function(){alert("Success!")}
}
});
And if you don't want to do that and just want to use the success callback, try something like this:
success: function (success) {
if (success || (success.length && success.length == 0)) { // this will almost definitely evaluate to true
console.log(success) // Do this to see what is actually being returned. I guarantee it isn't a boolean value.
alert("Success");
}
else {
alert("error");
}
}

How to execute jQuery AJAX calls in order?

I have an input field. Whenever there's change in the text in the input field, I make an ajax call to process.php
I need to handle all the responses. But some responses come early, whereas some come late, depending on the input. So the order of responses is not same as order of making ajax calls.
So right now I'm doing it by setting async: false
But I don't want the client side to be stuck due to async: false
$("#text_input").on("input", function() {
var password = $("#text_input").val();
var length = password.length;
$.ajax({
url: "process.php",
type: "POST",
async: false,
data: {
password: $(this).val()
}
}).done(function (data) {
console.log(data);
console.log(password + " : " + length);
}).fail(function( jqXHR, textStatus, errorThrown ) {
alert( "Request failed: " + textStatus + " , " + errorThrown );
});
});
I tried looking in promises, but did not understand whether it can be applied here.
How can I execute responses in order?
The problem with async is exactly that, that is asynchronous, that means that the code runs without waiting to finish. Therefore all your requests go to the server and once they start returning your code catches them and executes them.
If you want to handle them in order, you will need to build a queue and the code to handle the queue.
You should then assign an ordered number to all your requests which should then come in the response (so you know the proper order of the response).
Then you can add the response to the queue, and call a method which processes the queue, but that method only processes the queue in order, meaning that it only processes responses starting from 0, 1, 2, 3 etc... so if in the queue there is a result 5 and not a result 0, the queue won't be processed, the queue will be processed only if result 0 is there and so on...
Here is an example code, I haven't tested it but should work or at least should give you an idea on how to start :)
var currentOrder = 0;
var queue = [];
function processQueue() {
// Sort the queue
queue.sort(function(a, b) {
var aOrder = a.order;
var bOrder = b.order;
if (aOrder < bOrder) {
return -1;
}
if (aOrder > bOrder) {
return 1;
}
// Order is equal (this shouldn't happen)
return 0;
});
if (queue[0].order === currentOrder) {
doSomething(data);
queue.splice(0, 1); // Remove the first item from the queue as it's already processed
currentOrder++;
processQueue(); // Process the queue again
}
}
// Do something with the data
function doSomething(data) {
console.log(data);
}
$('#text_input').on('input', function() {
$.ajax({
url: 'process.php?order=' + order, // We send the order to the backend so it can be returned in the response
type: 'POST',
data: {
password: $(this).val()
}
}).done(function(data) {
// Data should contain the order somewhere, let's say for example it's a json and it's inside data.order
queue.push(data);
processQueue();
});
});
Assuming that you are only interested in the results of the latest ajax call, you can assign the value returned from the $.ajax call - a jqXHR object - to a variable and then abort the request when a new one is fired.
Something like:
var request = null;
$("#password_input").on("input", function() {
var password = $("#password_input").val();
var length = password.length;
// you can also check the type of the variable, etc.
if (request) {
request.abort();
}
request = $.ajax({
url: "process.php",
type: "POST",
...
Why not use setTimeout function to whenever they press some letter on your input field. you can do it just like this:
setTimeout(function(){
$.ajax({
url: "process.php",
type: "POST",
data: {
password: $(this).val()
}
}).done(function (data) {
console.log(data);
console.log(password + " : " + length);
}).fail(function( jqXHR, textStatus, errorThrown ) {
alert( "Request failed: " + textStatus + " , " + errorThrown );
});
}, 1000);
This is to setTimeout once the press on your input field and wait 1sec then when finished type on the input field it will generate the ajax after 1sec.

CefSharp - Get result of AJAX request

I am really new to CefSharps Chromium browser and have difficulty figuring out how to get the result of a jquery ajax request.
My first attempt was to pass my AJAX requesto to EvaluateScriptAsync. In fact the script works. It does exactly what I want, but I do not get any results/status codes, because my Cef-Task does not wait until AJAX has completed its work.
Here an example (just a sample code):
var tasks = pdBrowser.EvaluateScriptAsync(#"
(function(){
$.ajax({
type: ""POST"",
dataType: ""json"",
cache: false,
url: ""_resources/php/ajaxRequests.php"",
async: false,
data: {
action: ""insertCrossPlatform"",
type: """",
values: JSON.stringify(""foo bar"")
},
success: function(response) {
if (typeof response === 'string' && response.substring(0, 5) == ""ERROR"")
{
return response;
}
else
{
//pageReload();
return ""OK"";
}
},
error: function(xhr, textStatus, errorThrown) {
return errorThrown + ""\n"" + xhr.responseText;
},
complete: function() {
return ""COMPLETE"";
}
});
})();", null);
tasks.ContinueWith(t =>
{
if (!t.IsFaulted)
{
var response = t.Result;
if (response.Success)
{
if (response.Result != null)
{
MessageBox.Show(response.Result.ToString());
}
}
else
{
MessageBox.Show(response.Message, "Ein Fehler ist aufgetreten", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
}, TaskScheduler.Default);
Afterwards I have read that there is a SchemeHandler, but I do not properly understand how to implement it. Can anyone help me out?
Thanks in advance.
Firstly SchemeHandler is unlikely to be suitable in this scenario, you would typically implement a SchemeHandler when your providing the response.
Most people choose to bind an object, and call a method on their bound object when they wish to communicate with the parent application. See the FAQ for an example. https://github.com/cefsharp/CefSharp/wiki/Frequently-asked-questions#3-how-do-you-expose-a-net-class-to-javascript
With 49.0.0 you can implement ResponseFilter to gain access to the underlying response buffer, it's complex and not well documented, so if your not comfortable digging through reference C++ code then this option isn't for you. Here's a reference https://github.com/cefsharp/CefSharp/blob/cefsharp/49/CefSharp.Example/Filters/PassThruResponseFilter.cs#L17
Something that I did was create an element on the page through javascript with an ID that is the response of the ajax call. So for example, when you make an ajax call assign an ID to the ajax call.
When the ajax call returns, write an element on the page with the pre-assigned id and callback information. Then you can just use cefsharp to read the element content from the page and this will be your callback information.
var myDivElement =document.getElementById('textareaInfo');
if( myDivElement === null)
{
var input = document.createElement('textarea');
input.id = "textareaInfo";
input.value = "Test"
input.rows="4";
input.cols="50";
input.style="height:100%;width:900px;"
var dom = document.getElementsByClassName("page-body")[0];
dom.insertAdjacentElement('afterbegin', input)
}
Then later with ajax
var root = 'https://jsonplaceholder.typicode.com';
var _holder = callbackObj;
callbackObj.showMessage(""ajax"");
$.ajax({
url: root + '/posts/1',
contentType: 'application/json; charset=utf-8',
method: 'GET',
complete: function(data){
},
success: function(response) {
$(#'textareaInfo').value(response);
}
}).then(function(data) {
callbackObj.showMessage(data);
});
Then read the texarea from cefsharp in c#
chromeBrowser.GetMainFrame().EvaluateScriptAsync(function()...$(textareaInfo).value).Result
You can use PostMessage javascript method to notify .NET application:
CefSharp.PostMessage('Your data Here');
Here is .NET code example for headless browser:
var browser = new ChromiumWebBrowser("", null, RequestContext);
browser.JavascriptMessageReceived += (sender, e) =>
{
if ((string)e.Message.notificationid == "notification1")
{
// Your processing code goes here
}
};
browser.Load(destinationUrl);
browser.ExecuteScriptAsync("(function() { ... ; CefSharp.PostMessage({data: data, notificationid: 'notification1'});})()");

Uncaught ReferenceError: error is not defined in Ajax Callback

In my App, I get a list of Events from a Sharepoint Calendar List. That part works perfectly.
However after I get the collection of results, for each item I need to get the Display Form Url, which is another REST Call with the ListItem ID.
However I get the error below, but I still dont know what the problem might be
Uncaught ReferenceError: error is not defined App.js:87(anonymous function) App.js:87$.ajax.error App.js:40c jquery-1.9.1.min.js:22p.fireWith jquery-1.9.1.min.js:22k jquery-1.9.1.min.js:24send.r
I based my code on this answer:
https://sharepoint.stackexchange.com/questions/119236/how-to-get-the-display-form-url-using-rest
My adapted code is like this:
var SPHostUrl;
var SPAppWebUrl;
var ready = false;
// this function is executed when the page has finished loading. It performs two tasks:
// 1. It extracts the parameters from the url
// 2. It loads the request executor script from the host web
$(document).ready(function () {
var params = document.URL.split("?")[1].split("&");
for (var i = 0; i < params.length; i = i + 1) {
var param = params[i].split("=");
switch (param[0]) {
case "SPAppWebUrl":
SPAppWebUrl = decodeURIComponent(param[1]);
break;
case "SPHostUrl":
SPHostUrl = decodeURIComponent(param[1]);
break;
}
}
// load the executor script, once completed set the ready variable to true so that
// we can easily identify if the script has been loaded
$.getScript(SPHostUrl + "/_Layouts/15/SP.RequestExecutor.js", function (data) {
ready = true;
getItems();
});
});
function getListItemFormUrl(webUrl, listName, listItemId, formTypeId, complete, failure) {
$.ajax({
url: webUrl + "/_api/web/lists/GetByTitle('" + listName + "')/Forms?$select=ServerRelativeUrl&$filter=FormType eq " + formTypeId,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
var url = data.d.results[0].ServerRelativeUrl + '?ID=' + listItemId
complete(url);
},
error: function (data) {
failure(data);
}
});
}
// this function retrieves the items within a list which is contained within the parent web
function getItems() {
// only execute this function if the script has been loaded
if (ready) {
// the name of the list to interact with
var listName = "Events";
// the url to use for the REST call.
var url = SPAppWebUrl + "/_api/SP.AppContextSite(#target)" +
// this is the location of the item in the parent web. This is the line
// you would need to change to add filters, query the site etc
// "/web/lists/getbytitle('" + listName + "')/items?" +
"/web/lists/getbytitle('" + listName + "')/items?$select=Title,Category,EventDate,Description,EncodedAbsUrl,ID" +
"&#target='" + SPHostUrl + "'";
// create new executor passing it the url created previously
var executor = new SP.RequestExecutor(SPAppWebUrl);
// execute the request, this is similar although not the same as a standard AJAX request
executor.executeAsync(
{
url: url,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
// parse the results into an object that you can use within javascript
var results = JSON.parse(data.body);
var events = [];
$.each(results.d.results, function (i, obj) {
//Usage
getListItemFormUrl(SPAppWebUrl, 'Calendar', obj.ID, 4,
function (url) {
console.log('Display from url for list item: ' + url);
},
function (sender, args) {
console.log(JSON.stringify(error));
})
//use obj.id and obj.name here, for example:
var event = {
date: Date.parse(obj.EventDate).toString(),
type: obj.Category,
title: obj.Title,
description: obj.Description,
url: obj.EncodedAbsUrl + 'DispForm.aspx?ID=' + obj.ID
}
events.push(event);
});
var myJsonString = JSON.stringify(events);
$("#eventCalendarInline").eventCalendar({
jsonData: events,
openEventInNewWindow: true,
showDescription: true,
txt_GoToEventUrl: "Go to event"
});
Communica.Part.init();
},
error: function (data) {
// an error occured, the details can be found in the data object.
alert("Ooops an error occured");
}
});
}
}
Under //Usage:
function (sender, args) {
console.log(JSON.stringify(error));
})
error does not seem to be defined

Use .abort() to cancel existing ajax request if user sends another

I am attempting to follow the advice within this question to fit the following scenario:
On keyup, send an AJAX request to the server with the term in the input field. But if they continue to type, abort any existing AJAX requests so only one request is sent.
Here is my code as it stands:
jQuery(document).ready(function($) {
var $input = $('#s'),
inputVal = '',
inputCount = '';
function process_asr_request() {
$.ajax({
url: MyAjax.ajaxurl,
data: {
'action':'pondera_asr_request',
'inputVal' : inputVal
},
success:function(data) {
$('#search-results').append( data )
},
error: function(errorThrown){
console.log( errorThrown);
}
});
}
$input.on("keyup", function() {
// record the value of the input
inputVal = $input.val(),
// check the lenght on the value
inputCount = inputVal.length,
// define array for ajax requests
requests = [];
// Only process once there are 3 characters
if (inputCount > 2) {
// push ajax requests into the array
requests.push(
process_asr_request(i)
);
// loop through the array of requests
for(
var i = 0;
i < requests.length;
i++
)
// kill any queued requests
requests[i].abort();
};
});
});
I have two questions:
Is this approach valid for what I am looking to achieve
I get an "Uncaught TypeError: Cannot call method 'abort' of undefined" error with the above code. Where am I going wrong.
I'm fairly new to AJAX so please pardon my naivety.
Close, just need to return the xhr so you can abort it:
function process_asr_request(inputVal) {
return $.ajax({
url: MyAjax.ajaxurl,
data: {
'action':'pondera_asr_request',
'inputVal' : inputVal
},
success:function(data) {
$('#search-results').append( data )
},
error: function(errorThrown){
console.log( errorThrown);
}
});
}
Also this loop would be better written as below, so old xhrs are removed from requests:
var xhr;
while (xhr = requests.pop()) {
// kill any queued requests
xhr.abort();
}
requests.push(process_asr_request(inputVal));
Another note, requests should be outside the event loop if you want this to work and you have several globals in this function.
var requests = [];
$input.on("keyup", function() {
var inputVal = $input.val(),
// check the lenght on the value
inputCount = inputVal.length;
//...
});
var currXHR;
function process_asr_request() {
if(currXHR && currXHR.abort) currXHR.abort();
currXHR = $.ajax({
url: MyAjax.ajaxurl,
data: {
'action':'pondera_asr_request',
'inputVal' : inputVal
},
success:function(data) {
$('#search-results').append( data )
},
error: function(errorThrown){
console.log( errorThrown);
}
});
}

Categories