I have an existing function that returns an AJAX promise. I want to update this function to display a confirmation alert before running the AJAX call, but other parts of the code use this function and is already expecting a promise.
Here's what my original function looks like:
function doTheDeed() {
return $.ajax({
url: '/api/delete/123',
method: 'POST'
}).done(function () {
alert('The deed is done.');
});
}
doTheDeed().done(function {} { /*Do something else*/ });
Now I want to confirm with the user before running the AJAX call. How do maintain the API agreement of returning a promise, while waiting for the users confirmation or cancel?
function doTheDeed() {
bootbox.confirm('Are you sure?', function (result) {
if (result) {
// Too late to return a promise, promise should've been returned a long time ago
return $.ajax({
url: '/api/delete/123',
method: 'POST'
}).done(function () {
alert('The deed is done.');
});
} else {
//return what??
}
});
}
doTheDeed().done(function {} { /*Do something else*/ });
Do I need to conditionally return different promises based on the user's response?
I have an existing function that returns an AJAX promise. I want to update this function to display a confirmation alert before running the AJAX call, but other parts of the code use this function and is already expecting a promise.
Here's what my original function looks like:
function doTheDeed() {
return $.ajax({
url: '/api/delete/123',
method: 'POST'
}).done(function () {
alert('The deed is done.');
});
}
doTheDeed().done(function {} { /*Do something else*/ });
Now I want to confirm with the user before running the AJAX call. How do maintain the API agreement of returning a promise, while waiting for the users confirmation or cancel?
function doTheDeed() {
bootbox.confirm('Are you sure?', function (result) {
if (result) {
// Too late to return a promise, promise should've been returned a long time ago
return $.ajax({
url: '/api/delete/123',
method: 'POST'
}).done(function () {
alert('The deed is done.');
});
} else {
//return what??
}
});
}
doTheDeed().done(function {} { /*Do something else*/ });
Do I need to conditionally return different promises based on the user's response?
bootbox.confirm
call (which seems to be async as well, you can't just return
from the callback). Then chain it together with the ajax call.
– Bergi
Commented
Dec 24, 2015 at 13:51
You could use jQuery's Deferreds ?
function doTheDeed() {
var def = $.Deferred();
bootbox.confirm('Are you sure?', def.resolve);
return def.promise().then(function(result) {
return result ? $.post('/api/delete/123') : "no go";
});
}
doTheDeed().done(function (data) {
if (data == 'no go') {
// user declined
} else {
// item deleted
}
}).fail(function(err) {
// something failed
});
Building on Adeneo's answer, and adhering to the principle of promisifying at the lowest level, bootbox could be monkeypatched with a reusable promisification of bootbox.confirm()
, without having to hack into bootbox itself.
If you do this then it will be appropriate :
if(!bootbox.confirmAsync) {
bootbox.confirmAsync = function (challenge, noGoMessage) {
challenge = challenge || 'Are you sure?';
noGoMessage = noGoMessage || 'User declined';
return jQuery.Deferred(function (def) {
bootbox.confirm(challenge, function (confirmed) {
confirmed ? def.resolve() : def.reject(new Error(noGoMessage));
});
}).promise();
}
}
doTheDeed()
would then prise a totally conventional then chain starting with bootbox.confirmAsync(...)
, for example :
function doTheDeed () {
return bootbox.confirmAsync('Are you sure you want to delete?', 'User declined to delete')
.then(function (data) {
return $.post('/api/delete/123');
})
.then(null, function (err) {
// if user declined, then 'User declined to delete' will e back as err.message
console.log(err.message);
return err; // jQuery v<3.0
// throw err; // jQuery v>=3.0
});
}