Events Reference
7 minutes to readCustom JavaScript in a Flex DataPart uses the global CaspioFlex helper to listen for events that Caspio fires as the app runs. This page lists the functions, events, and event data you can use.
Functions
CaspioFlex.on(eventType, targetKey, eventKey, handler)
Registers a handler for an event on a DataPart or AppPage, and returns a function that removes the handler.
| Argument | Type | Description |
|---|---|---|
eventType | string | One of the events below. |
targetKey | string | The DataPart ID for DataPart and form events, or the AppPage ID for AppPage events. Insert it as a parameter. |
eventKey | string | A name you choose for this handler. Use it to replace or remove the handler later. |
handler | function or string | The code to run. A function receives the event data as its first argument. A string of code can refer to the event data as event. |
- Each combination of
eventType,targetKey, andeventKeyis unique. Registering the same combination again replaces the earlier handler. - If
eventTypeisn’t a supported event, orhandlerisn’t a function or string, nothing is registered and a warning is written to the browser console. - The returned function removes the handler. You can pass it an optional callback that runs after the handler is removed.
const unsub = CaspioFlex.on('dataPartReady', '[@datapartid:Customers.Customer form]', 'my-handler', function (event) {
console.log(event.appKey); // the DataPart ID
});
// Later, remove the handler
unsub();
// Or run code after the handler is removed
unsub(() => console.log('handler removed'));CaspioFlex.off(eventType, targetKey, eventKey)
Removes a handler you registered with CaspioFlex.on. Pass the same eventType, targetKey, and eventKey.
Events
| Event | Target | Fires when | Event data |
|---|---|---|---|
appPageReady | AppPage ID | The AppPage opens. | pageId |
appPageUnloaded | AppPage ID | The user leaves the AppPage. | pageId |
dataPartReady | DataPart ID | The DataPart’s data is loaded and shown. Fires again every time the data refreshes. | appKey |
dataPartUnloaded | DataPart ID | The DataPart is refreshed or the user leaves the page. | appKey |
formBeforeSubmit | DataPart ID of the form | A form is about to be sent, after its built-in validation passes. You can change or cancel the submission. | appKey, formData, cancelled, cancel() |
formSubmitted | DataPart ID of the form | A submission attempt finishes, including one that was cancelled. | appKey |
In the event data, appKey is the DataPart ID and pageId is the AppPage ID.
appPageReady
Fires once when the AppPage opens. Use it to customize Segment elements such as the menu or the page title. To customize a DataPart, use dataPartReady instead. Scripts in a DataPart run early enough to receive this event.
appPageUnloaded
Fires when the user leaves the AppPage. Use it to clean up anything you set up in appPageReady, such as timers or observers.
dataPartReady
Fires after the DataPart’s data is loaded and shown, so you can read fields, rows, cells, and chart elements right away. It fires when:
- The DataPart first renders.
- A linked Search Form is submitted, or a filter is applied.
- The user moves to another page of results.
- The user moves to another record in a Details/Update Form.
- A related DataPart refreshes this one.
- Parameters used by the DataPart’s data source change.
In forms with dropdown or lookup fields, the event fires only after every list has finished loading, so your handler never sees missing or outdated options.
If you register a dataPartReady handler after the data has already loaded, the handler runs right away with the most recent event data. Only dataPartReady works this way.
dataPartUnloaded
Fires when the current rendering of the DataPart is removed, either because the user leaves the page or because the DataPart refreshes with new data. After a refresh, dataPartReady fires again for the new rendering. Use this event to stop observers or release anything you created in dataPartReady.
formBeforeSubmit
Fires right before a form’s data is sent, after the form’s built-in validation passes. It is the only event you can cancel.
- Change the data: edit
event.formData. The changed values are what is submitted. - Cancel the submission: call
event.cancel().event.cancelledshows whether a handler has cancelled it. - Validate with another service: handlers can be
async. Caspio waits for each handler to finish before it continues.
formSubmitted
Fires after every submission attempt, including one that a formBeforeSubmit handler cancelled. The event data doesn’t say whether the submission succeeded, failed, or was cancelled.
How handlers run
- One at a time: when several handlers listen for the same event, they run in order, and each finishes before the next starts.
- All handlers run: in
formBeforeSubmit, the remaining handlers still run after one callsevent.cancel(). The submission is cancelled if any handler cancelled it. - Errors are contained: a handler that is empty, has a syntax error, or throws an error is skipped, the error is written to the browser console, and the other handlers still run.
Examples
Read form field values when the DataPart loads
const DATAPART_ID = '[@datapartid:Records.Record details]';
CaspioFlex.on('dataPartReady', DATAPART_ID, 'log-on-ready', event => {
const integerEl = document.getElementById('Integer-' + DATAPART_ID);
console.log('Integer:', integerEl ? integerEl.value : undefined);
});
CaspioFlex.on('formBeforeSubmit', DATAPART_ID, 'log-on-submit', event => {
console.log('Integer:', event.formData.Integer);
});
Color tabular report rows by a column value
dataPartReady fires again after every refresh, so the colors stay current when users search or page through results.
const DATAPART_ID = '[@datapartid:Sales.Sales report]';
const VALUE_COLUMN_INDEX = 1; // column to read, starting at 0
CaspioFlex.on('dataPartReady', DATAPART_ID, 'color-rows', () => {
const tbody = document.querySelector('[data-cb-appkey="' + DATAPART_ID + '"] .p-datatable-tbody');
if (!tbody) return;
for (const row of tbody.querySelectorAll('tr.tabular-row')) {
const cell = row.querySelectorAll('td')[VALUE_COLUMN_INDEX];
if (!cell) continue;
const value = parseFloat((cell.textContent || '').replace(/[^0-9.\-]/g, ''));
if (value > 100) {
row.style.backgroundColor = 'green';
} else if (value >= 50) {
row.style.backgroundColor = 'orange';
} else {
row.style.backgroundColor = 'red';
}
}
});
Change form data before it is submitted
CaspioFlex.on('formBeforeSubmit', '[@datapartid:Customers.Customer form]', 'normalize-phone', function (event) {
const raw = event.formData['PhoneNumber'];
if (raw) {
event.formData['PhoneNumber'] = raw.replace(/\D/g, '');
}
});
Cancel a submission based on a condition
CaspioFlex.on('formBeforeSubmit', '[@datapartid:Customers.Customer form]', 'validate-age', function (event) {
if (Number(event.formData['Age']) < 18) {
alert('You must be at least 18 years old.');
event.cancel();
}
});
Validate with another service before submitting
CaspioFlex.on('formBeforeSubmit', '[@datapartid:Customers.Customer form]', 'async-validate', async function (event) {
const response = await fetch('https://example.com/validate', {
method: 'POST',
body: JSON.stringify({ value: event.formData['SomeField'] }),
});
const result = await response.json();
if (!result.valid) {
event.cancel();
}
});
Run a handler only once
const unsub = CaspioFlex.on('formSubmitted', '[@datapartid:Customers.Customer form]', 'one-time-handler', function (event) {
console.log('Submitted once');
unsub();
});
Watch for changes inside a DataPart
Start aMutationObserver in dataPartReady and stop it in dataPartUnloaded. Wrap the code in a function so the observer variable is shared only by these handlers.
(function () {
const DATAPART_ID = '[@datapartid:Sales.Sales report]';
const observer = new MutationObserver(() => {
console.log('Content changed in DataPart', DATAPART_ID);
});
CaspioFlex.on('dataPartReady', DATAPART_ID, 'observe', () => {
const el = document.querySelector('[data-cb-appkey="' + DATAPART_ID + '"]');
if (el) observer.observe(el, { childList: true, subtree: true });
});
CaspioFlex.on('dataPartUnloaded', DATAPART_ID, 'stop-observing', () => {
observer.disconnect();
});
})();