Skip to main content

RunEvent Basic Concepts

Understanding the request and response structure is essential for implementing your runEvent handler.

Request Structure

When a form event occurs, your runEvent endpoint receives a JSON payload with the following structure:

{
"widgetName": "submitbtn",
"widgetEvent": "onClick",
"formData": {
"customerName": "John Doe",
"email": "john@example.com",
"phone": "+1234567890"
},
"widgetContext": "{\"additionalData\":\"value\"}",
"formCode": "CUSTOMERFORM",
"guid": "abc123-def456-ghi789",
"pluginCode": "NONE",
"projectGuid": "proj-123"
}

Request Fields

FieldTypeDescription
widgetNamestringName of the widget that triggered the event (lowercase)
widgetEventstringType of event (onClick, onChange, onTableLoadData, etc.)
formDataobjectDictionary of all current form field values
widgetValuestringWidget-specific value (optional, used for some events)
widgetContextstringAdditional context data as JSON string
formCodestringCode of the form being displayed
guidstringRecord UUID/GUID or "new" for new records
pluginCodestringPlugin code (usually "NONE")
projectGuidstringProject identifier

Special Fields for Datatable Events

For datatable events, additional fields may be present:

{
"DataTableMeta": {
"serverPaginationEnabled": true,
"rowsPerPage": 50,
"pageIndex": 0,
"nextToken": "",
"previousToken": "",
"paginationDirection": "first",
"rowCount": 0,
"qId": ""
}
}

Response Structure

Your runEvent endpoint must return a plain dictionary/object with these fields. You don't need any special classes - just return a JSON response:

{
"formData": { /* Dictionary of form field values */ },
"widgetData": [ /* Array of data for table widgets */ ],
"widgetsState": {
"visibility": { /* Widget visibility states */ },
"readOnly": { /* Widget read-only states */ }
},
"fieldAllowedValues": { /* Dropdown/select options */ },
"feCommand": [ /* Array of commands to execute */ ]
}

Response Fields Explained

FieldTypeDescription
formDataDictionaryCurrent values of all form fields. Update field values by modifying this object.
widgetDataArrayData for table widgets. Each item is a row with column values. Must include _id, _sk, _code fields.
widgetsStateObjectControls widget visibility and read-only state. Contains visibility and readOnly dictionaries.
fieldAllowedValuesDictionaryDropdown/select options. Key is field name, value is dictionary of option key-value pairs.
feCommandArrayCommands to execute on frontend (OpenRecord, CloseForm, Download, etc.).
tableMetaObjectPagination metadata for datatable widgets (optional, only for table events).
widgetRelatedDataObjectAdditional widget-related data like selected row IDs (optional).
Plain Dictionaries Only

You can use plain dictionaries/objects in your response - no special classes needed! The examples below show how to build the response using standard language features.

Response Examples

Update Form Field Values

// Prefill form fields with data
formData["customerName"] = "John Doe";
formData["email"] = "john@example.com";
formData["phone"] = "+1234567890";
formData["address"] = "123 Main St";
response["formData"] = formData;

Control Widget Visibility

// Hide specific widgets
response["widgetsState"] = new
{
visibility = new Dictionary<string, bool>
{
{ "phone", false },
{ "email", false },
{ "address", false }
},
readOnly = new Dictionary<string, bool>()
};

Control Widget Read-Only State

// Make fields read-only
response["widgetsState"] = new
{
visibility = new Dictionary<string, bool>(),
readOnly = new Dictionary<string, bool>
{
{ "customerName", true },
{ "email", true }
}
};

Populate Dropdown Options

// Populate dropdown with options
response["fieldAllowedValues"] = new Dictionary<string, object>
{
{
"statusField", new Dictionary<string, string>
{
{ "1", "New" },
{ "2", "In Progress" },
{ "3", "Completed" },
{ "4", "On Hold" }
}
},
{
"priorityField", new Dictionary<string, string>
{
{ "low", "Low Priority" },
{ "medium", "Medium Priority" },
{ "high", "High Priority" }
}
}
};

Load Table Widget Data

// Load data for a table widget
response["widgetData"] = new List<Dictionary<string, string>>
{
new Dictionary<string, string>
{
{ "_id", "customer-001" },
{ "_sk", "customer-001" },
{ "_code", "CUSTOMER" },
{ "name", "John Doe" },
{ "email", "john@example.com" },
{ "status", "Active" }
},
new Dictionary<string, string>
{
{ "_id", "customer-002" },
{ "_sk", "customer-002" },
{ "_code", "CUSTOMER" },
{ "name", "Jane Smith" },
{ "email", "jane@example.com" },
{ "status", "Pending" }
}
};
Required Table Row Fields

Table rows must include these fields:

  • _id - Unique identifier for the row
  • _sk - Sort key (usually same as _id)
  • _code - Form code for the record type

Without these fields, row actions (edit, delete, etc.) will not work properly.

Asynchronous Event Handling

When a form loads, multiple widgets may trigger their event handlers simultaneously. Your backend must be prepared to handle concurrent requests.

Example Scenario

User opens a form with:
- 2 datatable widgets
- 1 dropdown with dynamic options
- 1 onLoad event

Your runEvent endpoint receives 4 simultaneous requests:
1. onTableLoadData (table1)
2. onTableLoadData (table2)
3. onLoad (form)
4. onChange (dropdown)

Best Practices

  1. Make handlers stateless - Don't rely on request order
  2. Use proper concurrency handling - Ensure database operations are thread-safe
  3. Return consistent responses - Each request should get a complete response
  4. Optimize queries - Concurrent requests should not cause performance issues

Next Steps