Custom JS Editor
The Custom JS Editor is a Monaco-based code editor embedded directly in the App Studio Properties Editor panel. It provides syntax highlighting, auto-complete for the App Studio sandbox API, inline error markers, and a test runner for interactive debugging.
Opening the Editor
Editor Events — Choosing When Your Script Runs
Each Custom JS script is attached to a widget event. Select the event from the dropdown at the top of the editor:
| Event | When it fires | Common use |
|---|---|---|
onLoad | Once, when the widget first loads its data | Compute derived variables from initial data |
onDataChange | Every time the widget's data source reloads | Transform data before display; update app variables |
onRender | Every render cycle (use sparingly) | Dynamic chart series transformation |
onUserAction | When the user interacts (row click, button press) | Custom action logic; complex conditional navigation |
Auto-Complete and Type Hints
The editor provides IntelliSense for the App Studio sandbox API. Type widget. or variables. to see available methods and properties with inline documentation:
// Editor auto-completes the sandbox API:
widget. // → .data, .props, .widgetId, .type
variables. // → .get(name), .set(name, value), .getAll()
actions. // → .navigate(path), .openModal(id), .triggerWorkflow(id, inputs)
context. // → .userId, .tenantId, .roles, .displayName, .email
Inline Error Markers
The editor shows red underlines for:
- JavaScript syntax errors (caught before the script is saved)
- Calls to blocked APIs (e.g.,
fetch,window,document) — marked as sandbox violations - References to undefined variables in the sandbox scope
Test Runner
The editor includes a Test button that runs the script in the sandbox with the current widget's data from the canvas. The output panel shows:
console.logoutput from the script- Any sandbox violations detected at runtime
- Variables that were set during the test run
- Actions that would have been triggered (shown as log entries, not executed)
// Example script with console.log for debugging
function onDataChange(widget, variables, actions, context) {
const rows = widget.data.rows;
console.log('Row count:', rows.length);
const total = rows.reduce((sum, r) => sum + (r.dealValue || 0), 0);
console.log('Total deal value:', total);
variables.set('totalDealValue', total);
}
Script Structure
Each Custom JS script must export a function matching the selected event name:
// Template for an onDataChange script
function onDataChange(widget, variables, actions, context) {
// widget — current widget's data and props
// variables — read/write app variables
// actions — trigger app actions
// context — current user's identity and roles
// Your logic here...
}