AIO SDK Form: Submit Promises and Before Submit Promises
Purpose
AIO SDK Form provides two mechanisms for asynchronous custom logic around form submission:
beforeSubmitPromises- executed before the real form submission startssubmitPromises- executed during the submission process and can observe the real submission result throughformPromise
Both accept an array of functions, and each function must return a Promise.
What is a Promise in JavaScript
A Promise is an object that represents the result of an asynchronous operation.
A Promise has 3 states:
pending- the operation is still runningfulfilled- the operation completed successfullyrejected- the operation failed
Basic example
const promise = new Promise((resolve, reject) => {
const ok = true;
if (ok) {
resolve("success");
} else {
reject("error");
}
});Handling the result
promise
.then((result) => {
console.log("Success:", result);
})
.catch((reason) => {
console.log("Error:", reason);
})
.finally(() => {
console.log("This block always runs");
});What resolve and reject do
resolve(value)- completes the Promise successfullyreject(reason)- completes the Promise with an error
How Promises are used in AIO SDK Form
The form uses Promises in two places:
beforeSubmitPromises
Used for logic that must finish before the form is actually submitted.
Examples:
- confirm / modal before submit
- extra validation
- required user action before submission
- trigger before fetch
submitPromises
Used for logic that should run around an already started submit.
Examples:
- waiting modal
- custom success / failed UI
- changing modal text while request is in progress
- custom redirect after the server response
Callback signatures
beforeSubmitPromises
(ut, aioExchange, config) => PromiseArguments
ut-UTILSaioExchange- exchange object, can be used fortriggerconfig- current form config
submitPromises
(ut, formPromise, aioExchange, config) => PromiseArguments
ut-UTILSformPromise- Promise of the real form submission resultaioExchange- exchange objectconfig- current form config
How beforeSubmitPromises work
General logic
When the form is submitted, the SDK:
- collects form data
- validates the phone number
- disables the form
- runs all
beforeSubmitPromises - waits until all of them finish successfully
- only then starts the real
fetch
What resolve() means
If a callback inside beforeSubmitPromises calls resolve(), it means:
- this step completed successfully
- the form may continue the submit process
What reject() means
If a callback inside beforeSubmitPromises calls reject(), it means:
- submit is stopped
- the real
fetchis not started - an error is shown through
submitErrorCb
Important result
beforeSubmitPromises is a blocking pre-submit stage.
How submitPromises work
General logic
After beforeSubmitPromises finish successfully, the SDK:
- creates an internal
formPromise - starts all
submitPromises - immediately starts the real
fetch
What formPromise is
formPromise represents the result of the real form submission.
On successful submission:
formPromise.then((response) => {
// response = { success: true, url: "..." }
});On failed submission:
formPromise.catch((reason) => {
// reason = rejectedMessage
});What resolve() means inside submitPromises
resolve() only completes the Promise returned by your own callback.
It does not:
- start submit
- cancel submit
- control fetch
- control
submitErrorCb
What reject() means inside submitPromises
reject() only rejects your custom Promise.
It does not:
- cancel the real form submission
- stop fetch
- automatically trigger the form error flow
Important result
submitPromises is a non-blocking wrapper around submit, which can observe formPromise, but does not control whether the form is actually sent.
Form submission flow
The full submit flow is:
- user clicks submit
- SDK calls
preventDefault() - SDK collects form data
- SDK validates the phone number
- SDK calls
disableForms() - SDK runs
beforeSubmitPromises - if all
beforeSubmitPromisesfinish withresolve():- internal
formPromiseis created submitPromisesare started- real
fetchis started
- internal
- if the server returns
success: true:formPromiseis resolvedsuccessForms(...)is called- then
successFn(url)is called
- if the server returns an error, invalid JSON, or
success: false:formPromiseis rejected withrejectedMessagesubmitErrorCbis called
When to use beforeSubmitPromises
Use beforeSubmitPromises when you need to:
- allow or block submit
- show confirmation before submission
- wait for required user action
- run required logic before the form is sent
Example: submit confirmation
<script>
window.aioBus = window.aioBus || [];
window.aioBus.push({
type: "config",
config: {
form: {
beforeSubmitPromises: [
(ut, aioExchange, config) => new Promise((resolve, reject) => {
if (confirm("Submit the form?")) {
resolve();
} else {
reject();
}
})
]
}
}
});
</script>Example: trigger before submit
<script>
window.aioBus = window.aioBus || [];
window.aioBus.push({
type: "config",
config: {
form: {
beforeSubmitPromises: [
(ut, aioExchange, config) => new Promise((resolve, reject) => {
aioExchange.trigger("ad_name", "FORM YES");
resolve();
})
]
}
}
});
</script>Example: modal before submit
<script>
window.aioBus = window.aioBus || [];
window.aioBus.push({
type: "config",
config: {
form: {
beforeSubmitPromises: [
(ut, aioExchange, config) => new Promise((resolve, reject) => {
const modal = document.getElementById("before-promise-modal");
ut.openModal({
nativeElement: modal,
resolve: resolve,
reject: reject,
countDown: 5,
countDownStyle: "minutes",
countDownCb: () => {
ut.closeModal(modal);
resolve();
}
});
})
]
}
}
});
</script>When to use submitPromises
Use submitPromises when you need to:
- show waiting UI during submission
- handle success / failed result through
formPromise - update modal content after the server response
- build a custom success or error flow
Example: simple waiting modal
<script>
window.aioBus = window.aioBus || [];
window.aioBus.push({
type: "config",
config: {
form: {
successFn: (url) => null,
submitPromises: [
(ut, formPromise, aioExchange, config) => new Promise((resolve, reject) => {
const modal = document.getElementById("submit-modal");
formPromise
.then((response) => {
modal.querySelector("h1").innerText = "Success: " + response.url;
})
.catch((reason) => {
modal.querySelector("h1").innerText = "Failed: " + reason;
});
ut.openModal({
nativeElement: modal,
countDown: 3,
countDownStyle: "minutes",
countDownCb: () => {
resolve();
}
});
})
]
}
}
});
</script>Example: success / failed modal
<script>
window.aioBus = window.aioBus || [];
window.aioBus.push({
type: "config",
config: {
form: {
successFn: (url) => null,
submitPromises: [
(ut, formPromise, aioExchange, config) => new Promise((resolve, reject) => {
const waitingModal = document.getElementById("submit-promise-modal");
const successModal = document.getElementById("submit-success-modal");
const failedModal = document.getElementById("submit-failed-modal");
formPromise
.then((response) => {
ut.closeModal(waitingModal);
ut.openModal({ nativeElement: successModal });
})
.catch((reason) => {
ut.closeModal(waitingModal);
ut.openModal({ nativeElement: failedModal });
});
ut.openModal({
nativeElement: waitingModal,
countDown: 10,
countDownStyle: "minutes",
countDownCb: () => {
resolve();
}
});
})
]
}
}
});
</script>Example: custom redirect after success
<script>
window.aioBus = window.aioBus || [];
window.aioBus.push({
type: "config",
config: {
form: {
successFn: (url) => null,
submitPromises: [
(ut, formPromise, aioExchange, config) => new Promise((resolve, reject) => {
formPromise
.then((response) => {
setTimeout(() => {
window.location.href = response.url;
}, 2000);
})
.catch((reason) => {
console.log("Submit failed:", reason);
});
resolve();
})
]
}
}
});
</script>Difference between beforeSubmitPromises and submitPromises
| Parameter | beforeSubmitPromises | submitPromises |
|---|---|---|
| When it runs | Before real submit | During submit |
| Blocks form submission | Yes | No |
| Can stop fetch | Yes | No |
Receives formPromise | No | Yes |
| Suitable for confirm / pre-check | Yes | No |
| Suitable for submit UI | Limited | Yes |
Behavior of Multiple Promises
Both beforeSubmitPromises and submitPromises are handled through Promise.all(...).
This means:
- all Promises in the array are started in parallel
- this is not a sequential chain
Example
beforeSubmitPromises: [
promise1,
promise2,
promise3
]All three callbacks will start at the same time.
If sequential logic is required
If steps must run strictly one after another, it is better to combine them into a single Promise.
beforeSubmitPromises: [
(ut, aioExchange, config) => new Promise(async (resolve, reject) => {
try {
await step1();
await step2();
await step3();
resolve();
} catch (e) {
reject(e);
}
})
]Working with successFn
After a successful submission, the SDK calls successFn(json.url).
By default:
successFn: (url) => window.top.location.replace(url)If a custom success flow is needed, it is common to override it with:
successFn: (url) => nullAfter that, redirect logic can be handled manually inside submitPromises.
Reusable templates
beforeSubmitPromises template
beforeSubmitPromises: [
(ut, aioExchange, config) => new Promise((resolve, reject) => {
try {
// Logic before submit
resolve();
} catch (e) {
reject(e);
}
})
]submitPromises template
submitPromises: [
(ut, formPromise, aioExchange, config) => new Promise((resolve, reject) => {
try {
formPromise
.then((response) => {
// success
})
.catch((reason) => {
// failed
});
resolve();
} catch (e) {
reject(e);
}
})
]Summary
beforeSubmitPromises
Used for required logic before the form is sent.
- blocks submit
resolve()allows submissionreject()stops submission
submitPromises
Used for logic around form submission.
- does not block submit
- receives
formPromise - useful for custom UI and custom success / error flows
formPromise
This is the Promise of the real form submission result.
then(response)-> successful submitcatch(reason)-> failed submit