Variable events
Service, database, and other variables expose callback events around each invoke(). Use them to validate input, change payloads, reshape response data before it reaches widgets, and react to success or failure on that variable only.
For where variable events sit alongside app, page, and UI events, see Event handling overview. For app-wide service failures, use App.onServiceError instead of duplicating the same logic on every variable.
Wire handlers in Studio
- Open the Variables dialog for the page or app.
- Select the variable (for example
createEmployee). - Open the Events tab and choose the event.
- Studio adds a handler in the page or app script, for example
Page.createEmployeeonBeforeUpdate.
Handler names concatenate the variable name and event name: Page.{variableName}on{EventName}.
Which variables expose these events
Studio lists these callbacks on Service, Live, and Database CRUD variables, and on Login and Logout variables. In-memory Model variables and Device variables do not use this invoke lifecycle.
Invocation order
When you call invoke() on a service or live variable, handlers run in this order:
| Order | Event | Purpose |
|---|---|---|
| 1 | onBeforeUpdate | Validate or change input; return false to cancel the call |
| 2 | onResult | Run after any response (success or failure) |
| 3 | onBeforeDatasetReady | Transform response data before dataSet is assigned |
| 4a | onSuccess | Run only when the call succeeds and dataSet is updated |
| 4b | onError | Run only when the call fails |
onResult always runs when a response arrives. onSuccess and onError are mutually exclusive for that invocation.
To block a call before it starts, use onBeforeUpdate (return false) or configure In flight behavior on the variable.
onBeforeUpdate
Runs just before the variable calls the service. Validate or change inputData. Return false to cancel the call.
Page.createEmployeeonBeforeUpdate = function (variable, inputData, options) {
if (!inputData.employeeName) {
App.Actions.notify({
message: "Employee name is required",
severity: "error"
});
return false;
}
inputData.createdDate = new Date();
return true;
};
Database CRUD variables use specialized before-events instead of onBeforeUpdate:
- READ →
onBeforeListRecords - UPDATE →
onBeforeUpdateRecord - INSERT →
onBeforeInsertRecord - DELETE →
onBeforeDeleteRecord
Other variable types use onBeforeUpdate.
onBeforeDatasetReady
Runs after the service returns and before the variable dataSet is updated. Return the data shape you want bound to lists, forms, and other widgets.
Page.createEmployeeonBeforeDatasetReady = function (variable, data) {
let selectedDeviceIds = Page.Widgets.DevicePicker.selecteddevices
.map(device => device.id);
return data.filter(emp =>
selectedDeviceIds.includes(emp.devicesMappedId)
);
};
onResult
Runs when the service returns, whether the call succeeded or failed. Use it to normalize shape (for example wrap a single object in an array for a list).
Page.createEmployeeonResult = function (variable, data, operation) {
if (data && !Array.isArray(data)) {
variable.dataSet = [data];
}
};
onSuccess
Runs after a successful call, once dataSet is updated.
Page.createEmployeeonSuccess = function (variable, data, operation) {
App.Actions.notify({
message: "Employee created successfully",
severity: "success"
});
Page.Variables.getEmployees.invoke();
Page.Widgets.editEmployeeDialog.close();
};
onError
Runs when the variable call fails. Handle errors for this variable here; use App.onServiceError when the same handling should apply to every service in the app.
Page.createEmployeeonError = function (variable, error, operation) {
App.Actions.notify({
message: error.message || "Unable to create employee",
severity: "error"
});
if (error.details && error.details.validationErrors) {
Page.Widgets.employeeForm.setErrors(error.details.validationErrors);
}
};