Reputation: 342
I have a form with validation code that requires an Ajax call to a database, the return value from which must be handled before the form is submitted. I've tried using promises as below but am obviously misundersanding the syntax. The return values are still in the required order. Your help will be greatly valued.
The key parts of the code are:
// checks form submission
$('#ml_doaction').on('click', function(e) {
e.preventDefault();
var isOK = true;
$('form#managelists :input').each(function(){
var id = this.id;
switch(id)
{
case 'maillist':
checkNewListName(id).then(function(data) {
if(data === false) {
isOK = false;
}
});
break;
// etc ....
}
});
if(isOK === true) {
// submit form
$('form#managelists').submit();
}
});
function checkNewListName(id)
{
var listVal = $('#' + id).val();
var dfd = $.Deferred();
$.ajax({
type: 'POST',
data:{'checklistexists': listVal},
url:'/php/ajax/validation-ajax.php',
success:function(response){
if(response == 'listexists') {
dfd.resolve(false);
}
else {
dfd.resolve(true);
}
}
});
return dfd.promise();
}
Upvotes: 1
Views: 5606
Reputation: 338406
First off, let's clean up your checkNewListName()
function. It's the purpose of that function to take a list name and return true
if the given list exists on the server, and false
otherwise.
The server takes a moment to figure this out, so we can ask the question, and the answer will arrive some time later. This can be solved through promises, as you did, but when we take into account that jQuery Ajax requests already are promises, we can make the function much simpler (and give it a better name - my convention is, functions that return promises are called somethingAsync
):
function checkListNameExistsAsync(listName) {
return $.post('/php/ajax/validation-ajax.php', {
checklistexists: listName
}).then(function (response) {
return response == 'listexists';
});
});
}
This takes a list name and returns a promise for true
or false
. It has no DOM dependency, so we can test it in the console:
checkListNameExistsAsync('foobar').then(function (exists) {
console.log(exists);
});
which will probably log false
.
With that out of the way, we can call this in a loop and get a bunch of promises.
First step, getting all the list names we want to check (this gives an array of strings):
var allListNames = $('form#managelists :input').map(function () {
return this.value;
}).toArray();
Second step, requesting checks for all of them (this gives an array of promises for Boolean values):
var allChecks = allListNames.map(checkNewListNameAsync);
Third, we need to wait until all these promises have settled. This can be done through Promoise.all()
, or with jQuery's own utility function, $.when()
:
var overallResult = $.when.apply($, allChecks);
overallResult
is another promise, which resolves when all the input promises have resolved. So we can attach a .then
handler, which will receive the results of all input promises in its arguments
. If any argument is equal to true
, at least one of the lists already exists:
overallResult.then(function () {
if (Array.from(arguments).includes(true)) {
alert("At least one list already exists!");
} else {
$('form#managelists').submit();
}
});
The arguments will be in the same order as the input list (allListNames
), so you can use that to figure out which list exists.
Don't forget to attach a .fail()
handler to overallResult
, to catch any errors.
Upvotes: 2
Reputation: 18155
The then()
callback gets executed if the AJAX is successful. Check the isOK
flag (client side validation) and ensure the result from the AJAX call is valid (server side validation). If both pass, do the form submission.
// checks form submission
$('#ml_doaction').on('click', function(e) {
e.preventDefault();
var isOK = true;
$('form#managelists :input').each(function(){
var id = this.id;
switch(id)
{
checkNewListName(id).then(function(data) {
if(isOK && data !== false) {
// submit form
$('form#managelists').submit();
}
});
break;
// etc ....
}
});
});
Upvotes: 1