Reputation: 7354
Bear with me--I realize what I'm doing below is stupid, I just can't see solutions online to un-stupidify myself :)
I have the following function, which I would like to have return a promise:
function getInput() {
var form = $("form.prompt"); // some form in the DOM, this is working fine
return Promise.resolve(form.show().focus().submit(function(event) {
var input = $(this).find("input");
var inputVal = input.val();
alert("form submitted! input val is " + inputVal);
event.preventDefault();
resolve(inputVal);
}));
}
I call that function and try to wait for the promise to resolve:
getInput().then(function(response) {
alert("input resolved; response is " + response);
});
I would like to see the following behavior: no alerts until I submit the form, after which I would see "form submitted!" and then "input resolved".
Instead, I see "input resolved" immediately. (Obviously, after that, once I submit the form I see "form submitted!".)
I realize I'm completely not handling the .submit() function properly; I'm treating it like it is thennable, and will be cast by Promise.resolve() into a proper promise. Clearly, that's not happening. I gather that .submit() has some other value or properties and that Promise.resolve() is ending its promise evaluation chain right away, which is why the then() executes immediately.
Moreover, I realize I'm handling .submit() as if it's a single event I'm waiting on, whereas it's a callback function that is meant to be run every time the form submits.
My question is, what's the right way to do what I'm trying to do? Which is, postpone execution of some code (represented here by the "input resolved" alert) until a particular form is submitted once? It's like I need a function that would loop with a short Timeout until it sees that a flag has been set by the .submit() callback...
Upvotes: 3
Views: 369
Reputation: 7354
Taking @dsfq's answer even further --
Turns out you can nest promises in a flattened way that makes the code more elegant. This trick inspired by https://parse.com/docs/js_guide#promises-series -- please tell me if this is documented for native js promises anywhere!
(code is live at http://jsfiddle.net/q306nzk2/6/ )
function getInput() {
return new Promise(function (resolve, reject) {
var $form = $("form.prompt").one('submit', function (event) {
var input = $form.find("input").val();
event.preventDefault();
resolve(input);
});
});
};
// start by making essentially a "blank", resolved promise:
var prm = Promise.resolve();
// next, append a function to perform, which returns a promise;
// this will cause prm to effectively "block" until the promise
// getInput returns is resolved
prm = prm.then(function() {
return getInput().then(function(response) {
alert("input resolved; response is " + response);
});
});
// do it again -- this function won't execute until the previous promise resolves!
prm = prm.then(function() {
return getInput().then(function(response) {
alert("input resolved again; response is " + response);
});
});
Upvotes: 0
Reputation: 193271
You can totally do it. It may look like this:
function getInput() {
return new Promise(function (resolve, reject) {
var $form = $("form.prompt").on('submit', function (event) {
var input = $form.find("input").val();
event.preventDefault();
resolve(input);
});
});
}
getInput().then(function (response) {
alert("input resolved; response is " + response);
});
But this example perfectly demonstrates that Promises are not the right tool for the task: you can resolve or reject it only once.
Upvotes: 1
Reputation: 10924
I think you want this:
function getInput() {
var form = $("form.prompt"); // some form in the DOM, this is working fine
var deferred = $.Deferred();
form.show().focus().one("submit", function(event) {
var input = $(this).find("input");
var inputVal = input.val();
alert("form submitted! input val is " + inputVal);
event.preventDefault();
deferred.resolve(inputVal);
});
return deferred.promise();
}
Upvotes: 2