I want to show a waiting dialog while a synchronous ajax is made.
I using a Smart Wizard, to change between step one to step to i have to validate some data to do that i have to make 3 ajax call one after the other and while this is done i want to show a waiting dialog. This is what I'm doing.
if (indexes.fromStep==1) {
res=false;
var validatorResult = validator.checkAll($("#install_modbus_form"))
if (validatorResult) {
$("#modal_loader").modal()
$.ajax({
type: "post",
url: url1,
async: false,
dataType: "json",
data:{
data
},
success: function(response)
{
if (response.success)
{
$.ajax({
type: "post",
url: url2,
async: false,
dataType: "json",
data:{
data
},
success: function(response)
{
if (response.success)
{
$.ajax({
type: "post",
url: url3,
async: false,
dataType: "json",
data:{
data
},
success: function(response)
{
if (response.success)
{
//make magic here
res=true;
}
},
failure:function()
{
waitingDialog.hide()
res=false
},
error:function(a,b,c) {
waitingDialog.hide()
res=false
}
)
}
},
failure:function()
{
waitingDialog.hide()
res=false
},
error:function(a,b,c) {
waitingDialog.hide()
res=false
}
)
}
},
failure:function()
{
waitingDialog.hide()
res=false
},
error:function(a,b,c) {
waitingDialog.hide()
res=false
}
)
$("#modal_loader").modal('hide')
return res;//if true change step
}
}
I have trie use beforeSend to show the waiting dialog, also i have trie to use setTimeout but the waiting dialog is not show and the smart wizard dont go forward
Hope you can help, Im new in jquery.
Sorry for the bad english
On the assumption that you are using jQuery-Smart-Wizard, the solution lies in :
the construction of your onLeaveStep event handler, and (or including)
a modified version of the validation code shown in the question.
Fortunately, even though the plugin does not natively support asynchronism, it is fairly simple to make it do so. Essentially, what you need to do is :
to return false from the onLeaveStep callback,
to establish a promise which fulfills on successful validation, or rejects on failure,
to call .smartWizard('goForward') from the promise's success handler,
to call .smartWizard('showError') from the promise's error handler.
Based on smartWizard's ReadMe.md, here's a framework for performing synchronous and asynchronous validations :
$(document).ready(function() {
var waitingDialog = $('#whatever'); // ???
// Smart Wizard
$('#wizard').smartWizard({
onLeaveStep: leaveAStepCallback,
onFinish: onFinishCallback
});
function leaveAStepCallback(obj, context) {
alert("Leaving step " + context.fromStep + " to go to step " + context.toStep);
var returnValue;
switch(context.fromStep) {
case 1: // asynchronous
if (validator.checkAll($("#install_modbus_form"))) {
$("#modal_loader").modal();
waitingDialog.show();
validateStep1() // validateStep1() returns a promise
.then(function() {
// You will arrive here only if all three ajax calls were successful and all three responded with a truthy `response.success`.
$('#wizard').smartWizard('goForward'); // advance to next step
}, function(e) {
// You will arrive here on validation failure
$('#wizard').smartWizard('showError', e.message); // something went wrong
}).always(function() {
// You will arrive here on validation success or failure
waitingDialog.hide(); // the waiting is over
$("#modal_loader").modal('hide'); // ???
});
} else {
$('#wizard').smartWizard('showError', 'validator.checkAll() failed');
}
returnValue = false; // *must* return false to remain at step 1. If validation is successful, `.smartWizard('goForward')` will be executed later (see above).
break;
case 2: // synchronous
returnValue = validateStep2(); // validateStep2() returns true of false
break;
case 3:
...
break;
}
return returnValue; // true or false
}
// And here's the all-important `validateStep1()` :
function validateStep1() {
var sequence = [
{ url: 'url/1', data: {...} },
{ url: 'url/2', data: {...} },
{ url: 'url/3', data: {...} }
];
return sequence.reduce(function(promise, item, i) {
return promise.then(function() {
return $.ajax({
'type': 'post',
'url': item.url,
'dataType': 'json',
'data': item.data
}).then(function(response, textStatus, jqXHR) {
return response.success ? response : $.Deferred().reject(jqXHR, 'response.success not truthy at validation stage ' + i); // note: need to mimic jQuery.ajax's error signature.
});
});
}, $.when()) // starter promise for the reduction
.then(null, function(jqXHR, textStatus, errorThrown) {
return $.Deferred().reject(new Error(textStatus || errorThrown));
});
}
function validateStep2() {
// if validation here is synchronous, then return true of false
if(....) {
return true;
} else {
return false;
}
}
function validateStep3() {
...
}
// etc.
function onFinishCallback(objs, context) {
if(validateAllSteps()) {
$('form').submit();
}
}
function validateAllSteps() {
var isStepValid = true;
// all step validation logic
return isStepValid;
}
});
Notes :
the branching logic is in the onLeaveStep callback.
validateStep1() uses a chained promise pattern to sequence the three ajax calls.
if validateAllSteps() needs to repeat the step1 validation, then you will need call validateStep1().then(...) again, or chain from a previously cached promise.
As you can see, some aspects above are incomplete so there's still some work to do.
Related
I have read a lot about promises but I'm still not sure how to implement it.
I wrote the folowing AJAX call with async=false in order for it to work, but I want to replace it with promise as I saw that async=false is deprecated.
self.getBalance = function (order) {
var balance;
$.ajax({
url: "/API/balance/" + order,
type: "GET",
async: false,
success: function (data) {
balance = data;
},
done: function (date) {
}
});
return balance;
}
Would you be able to help me? I just need an example to understand it.
As first point, you don't want to set an asynchronous call to false as it will lock the UI.
You could simplify your method returning the ajax object and the handle it as a promise.
self.getBalance = function (orderNumber) {
return $.ajax({
url: "/Exchange.API/accountInfo/balance/" + orderNumber,
type: "GET",
});
};
var demoNumber = 12;
self.getBalance(demoNumber).then(function(data){
console.log(data);
},function(err){
console.log("An error ocurred");
console.log(err);
});
Return promise object from getBalance method:
self.getBalance = function (orderNumber) {
return $.ajax({
url: "/Exchange.API/accountInfo/balance/" + orderNumber,
type: "GET"
});
}
and use it later like this:
service.getBalance().then(function(balance) {
// use balance here
});
I need to combine three methods:
An AJAX to check the existence of a code
If the code exists, confirm whether to overwrite
Overwrite
I've written three methods that return a $.Deferred in order to chain them together with .done(), which are below:
function checkFunction() {
var code = $("#code").val();
return $.ajax({
url: "${pageContext.request.contextPath}/dataManagement/codeMaintenance/check",
method: "POST",
async: false,
data: {
"reasonCode": code
},
success: function(response, textStatus, jqXHR) {
var exists = response.dataMap.exists;
console.log("Code exists: " + exists);
if (exists == true) {
return $.Deferred().resolve(true);
} else {
return $.Deferred().reject();
}
}, error: function() {
return $.Deferred().reject("AJAX ERROR");
}
});
};
var confirmFunction = function(codeExists) {
console.log("Confirming overwrite");
if (codeExists == true) {
var confirm = confirm("Code Exists: Do you wish to overwrite?");
if (confirm == true) {
return $.Deferred(true);
} else {
return $.Deferred(false);
}
} else {
return $.Deferred(true);
}
};
var saveFunction = function() {
console.log("Saving");
var code = $("#code").val();
return $.ajax({
url: "${pageContext.request.contextPath}/dataManagement/codeMaintenance/save",
method: "POST",
data: {
"reasonCode": code
},
success: function(response, textStatus, jqXHR) {
alert("test");
return $.Deferred(true);
}
});
};
I then attempt to execute via this line:
checkFunction().done(confirmFunction(codeExists)).done(saveFunction());
Unfortunately, the parameter I set on the $.Deferred from the first method does not get passed as a parameter to confirmFunction().
What am I doing wrong?
Jason
In short: plenty.
You try to use return inside of asynchronous functions in the success handlers of your $.ajax() calls.
Here you pass the result of the function call and not a reference of the function as callbacks:
checkFunction().done(confirmFunction(codeExists)).done(saveFunction());
This should be more like this:
checkFunction().done(confirmFunction).done(saveFunction);
In confirmFunction() you return a new Deferred object. What you should do is create a Deferred object, return the respective promise and then resolve/reject the Deferred object. So, e.g., your checkFunction() function should look like this:
function checkFunction() {
var code = $("#code").val();
// create deferred object
var result = $.Deferred();
return $.ajax({
url: "${pageContext.request.contextPath}/dataManagement/codeMaintenance/check",
method: "POST",
async: false,
data: {
"reasonCode": code
},
success: function(response, textStatus, jqXHR) {
var exists = response.dataMap.exists;
console.log("Code exists: " + exists);
if (exists == true) {
result.resolve(true);
} else {
result.reject();
}
}, error: function() {
result.reject("AJAX ERROR");
}
});
return result.promise();
}
Below you will see some code to set the currently logged in user for an extjs 4 application. If I have the alert uncommented, the code seems to wait until the alert is accepted before the code continues (it seems). That allows enough time for the asynchronous call to complete with a success. If I comment out the alert, the variable "employeeFilter" never gets set because the AJAX call didn't come back in time. In which case, it sets the "employeeFilter" to null instead. How can I fix this so it waits until the AJAX response comes back in success?
var loggedInUserId = null;
Ext.Ajax.request({
url: '/Controls/UserList/UserService.asmx/GetLoggedInUserId',
method: 'POST',
jsonData: { 'x': 'x' },
success: function (response, opt) {
loggedInUserId = Ext.decode(response.responseText).d;
},
failure: function (response) {
}
});
//alert(loggedInUserId);
var employeeFilter = loggedInUserId;
var projectFilter = '-1';
I would have done this.
var employeeFilter;
Ext.Ajax.request({
url: '/Controls/UserList/UserService.asmx/GetLoggedInUserId',
method: 'POST',
jsonData: { 'x': 'x' },
success: function (response, opt) {
employeeFilter = Ext.decode(response.responseText).d;
//Do here whatever you need to do once the employeeFilter is set. probably call a function and pass the employee filter as parameter.
},
failure: function (response) {
}
});
var projectFilter = '-1';
I'm trying to create a global handler that gets called before the ajax success callback. I do a lot of ajax calls with my app, and if it is an error I return a specific structure, so I need to something to run before success runs to check the response data to see if it contains an error code bit like 1/0
Sample response
{"code": "0", "message": "your code is broken"}
or
{"code": "1", "data": "return some data"}
I can't find a way to do this in jQuery out of the box, looked at prefilters, ajaxSetup and other available methods, but they don't quite pull it off, the bets I could come up with is hacking the ajax method itself a little bit:
var oFn = $.ajax;
$.ajax = function(options, a, b, c)
{
if(options.success)
{
var oFn2 = options.success;
options.success = function(response)
{
//check the response code and do some processing
ajaxPostProcess(response);
//if no error run the success function otherwise don't bother
if(response.code > 0) oFn2(response);
}
}
oFn(options, a, b, c);
};
I've been using this for a while and it works fine, but was wondering if there is a better way to do it, or something I missed in the jQuery docs.
You can build your own AJAX handler instead of using the default ajax:
var ns = {};
ns.ajax = function(options,callback){
var defaults = { //set the defaults
success: function(data){ //hijack the success handler
if(check(data)){ //checks
callback(data); //if pass, call the callback
}
}
};
$.extend(options,defaults); //merge passed options to defaults
return $.ajax(options); //send request
}
so your call, instead of $.ajax, you now use;
ns.ajax({options},function(data){
//do whatever you want with the success data
});
This solution transparently adds a custom success handler to every $.ajax() call using the duck punching technique
(function() {
var _oldAjax = $.ajax;
$.ajax = function(options) {
$.extend(options, {
success: function() {
// do your stuff
}
});
return _oldAjax(options);
};
})();
Here's a couple suggestions:
var MADE_UP_JSON_RESPONSE = {
code: 1,
message: 'my company still uses IE6'
};
function ajaxHandler(resp) {
if (resp.code == 0) ajaxSuccess(resp);
if (resp.code == 1) ajaxFail(resp);
}
function ajaxSuccess(data) {
console.log(data);
}
function ajaxFail(data) {
alert('fml...' + data.message);
}
$(function() {
//
// setup with ajaxSuccess() and call ajax as usual
//
$(document).ajaxSuccess(function() {
ajaxHandler(MADE_UP_JSON_RESPONSE);
});
$.post('/echo/json/');
// ----------------------------------------------------
// or
// ----------------------------------------------------
//
// declare the handler right in your ajax call
//
$.post('/echo/json/', function() {
ajaxHandler(MADE_UP_JSON_RESPONSE);
});
});
Working: http://jsfiddle.net/pF5cb/3/
Here is the most basic example:
$.ajaxSetup({
success: function(data){
//default code here
}
});
Feel free to look up the documentation on $.ajaxSetup()
this is your call to ajax method
function getData(newUrl, newData, callBack) {
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
url: newUrl,
data: newData,
dataType: "json",
ajaxSuccess: function () { alert('ajaxSuccess'); },
success: function (response) {
callBack(true, response);
if (callBack == null || callBack == undefined) {
callBack(false, null);
}
},
error: function () {
callBack(false, null);
}
});
}
and after that callback success or method success
$(document).ajaxStart(function () {
alert('ajax ajaxStart called');
});
$(document).ajaxSuccess(function () {
alert('ajax gvPerson ajaxSuccess called');
});
I'm trying to return true or false to a function depending on the response of an AJAX function inside of it but I'm not sure how should I do it.
(function($) {
$('#example').ajaxForm({
beforeSubmit : function(arr, $form, options) {
var jsonStuff = JSON.stringify({ stuff: 'test' });
$.post('/echo/json/', { json: jsonStuff }, function(resp) {
if (resp.stuff !== $('#test').val()) {
// Cancel form submittion
alert('Need to type "test"');
return false; // This doesn't work
}
}, 'json');
},
success : function() {
alert('Form sent!');
}
});
})(jQuery);
I made a fiddle to illustrate this better:
http://jsfiddle.net/vengiss/3W5qe/
I'm using jQuery and the Malsup's Ajax Form plugin but I believe this behavior is independent of the plugin, I just need to return false to the beforeSubmit function depending on the POST request so the form doesn't get submitted every time. Could anyone point me in the right direction?
Thanks in advance!
This is not possible to do when dealing with async functions. The function which calls post will return immediately while the ajax call back will return at some point in the future. It's not possible to return a future result from the present.
Instead what you need to do is pass a callback to the original function. This function will eventually be called with the result of the ajax call
var makePostCall = function(callback) {
$.post('/echo/json/', { json: jsonStuff }, function(resp) {
if (resp.stuff !== $('#test').val()) {
// Cancel form submittion
alert('Need to type "test"');
callback(false);
} else {
callback(true);
}}, 'json');
};
Then switch the code which expected a prompt response from makePostCall to using a callback instead.
// Synchronous version
if (makePostCall()) {
// True code
} else {
// false code
}
// Async version
makePostCall(function (result) {
if (result) {
// True code
} else {
// False code
}
});
you can put async:false parameter to ajax request then you can control future responce and send back the result to parent. see following main lines enclosed within ***
add: function (e, data) {
//before upload file check server has that file already uploaded
***var flag=false;***
$.ajax(
{
type: "POST",
dataType:'json',
url:"xyz.jsp",
***async:false,***
data:{
filename : upload_filename,
docname : upload_docname,
userid : upload_userid,
},
success:function(data)
{
***flag=true;***
},
error:function(request,errorType,errorMessage)
{
alert ('error - '+errorType+'with message - '+errorMessage);
}
});
***return flag;***
}