Form Lifecycle Events
Form lifecycle events allow you to hook into key moments in a form's existence: when it loads, saves, or closes.
Event Types
| Event | Triggered When |
|---|---|
onLoad | Form finishes loading/rendering |
onSave | Form save is triggered |
onClose | Form is about to close |
onBeforeSave | Before form data is saved (validation) |
onLoad Event
Triggered: When the form finishes loading and all widgets are initialized Use For: Initialize form data, load dropdown options, set default values
Request Example
{
"widgetName": "form",
"widgetEvent": "onLoad",
"formData": {},
"formCode": "CUSTOMERFORM",
"guid": "new"
}
Load Initial Data
- C# / .NET
- PHP
if (widgetName == "FORM" && eventType == "ONLOAD")
{
var guid = requestBody.GetProperty("guid").GetString();
if (guid != "new")
{
// Load existing record
var customer = await _dbContext.Customers
.FirstOrDefaultAsync(c => c.Id.ToString() == guid);
if (customer != null)
{
formData["customerName"] = customer.Name;
formData["email"] = customer.Email;
formData["phone"] = customer.Phone;
formData["address"] = customer.Address;
formData["status"] = customer.StatusId.ToString();
response["formData"] = formData;
}
}
else
{
// Set default values for new record
formData["status"] = "1"; // Default to "New" status
formData["createdDate"] = DateTime.Now.ToString("yyyy-MM-dd");
formData["country"] = "US"; // Default country
response["formData"] = formData;
}
// Load dropdown options
var statuses = await _dbContext.Statuses.ToListAsync();
var countries = await _dbContext.Countries.ToListAsync();
response["fieldAllowedValues"] = new Dictionary<string, object>
{
{
"status", statuses.ToDictionary(
s => s.Id.ToString(),
s => s.Name
)
},
{
"country", countries.ToDictionary(
c => c.Code,
c => c.Name
)
}
};
}
if ($widgetName === 'FORM' && $eventType === 'ONLOAD') {
$guid = $requestData['guid'];
if ($guid !== 'new') {
// Load existing record
$customer = DB::table('customers')
->where('id', $guid)
->first();
if ($customer) {
$formData['customerName'] = $customer->name;
$formData['email'] = $customer->email;
$formData['phone'] = $customer->phone;
$formData['address'] = $customer->address;
$formData['status'] = $customer->status_id;
$response['formData'] = $formData;
}
} else {
// Set default values for new record
$formData['status'] = '1'; // Default to "New" status
$formData['createdDate'] = date('Y-m-d');
$formData['country'] = 'US'; // Default country
$response['formData'] = $formData;
}
// Load dropdown options
$statuses = DB::table('statuses')->pluck('name', 'id')->toArray();
$countries = DB::table('countries')->pluck('name', 'code')->toArray();
$response['fieldAllowedValues'] = [
'status' => $statuses,
'country' => $countries
];
}
Set Widget Visibility Based on Permissions
- C# / .NET
- PHP
if (widgetName == "FORM" && eventType == "ONLOAD")
{
// Get current user permissions
var userId = requestBody.GetProperty("userId").GetString();
var user = await _dbContext.Users.FindAsync(userId);
var visibility = new Dictionary<string, bool>();
var readOnly = new Dictionary<string, bool>();
if (user.Role == "Viewer")
{
// Viewers can only see limited fields
visibility["sensitiveData"] = false;
visibility["financialInfo"] = false;
// Make all fields read-only
readOnly["customerName"] = true;
readOnly["email"] = true;
readOnly["phone"] = true;
}
else if (user.Role == "Editor")
{
// Editors can see all but can't edit sensitive data
visibility["sensitiveData"] = true;
visibility["financialInfo"] = true;
readOnly["sensitiveData"] = true;
}
// Admin has full access (no restrictions)
response["widgetsState"] = new
{
visibility = visibility,
readOnly = readOnly
};
}
if ($widgetName === 'FORM' && $eventType === 'ONLOAD') {
// Get current user permissions
$userId = $requestData['userId'];
$user = DB::table('users')->find($userId);
$visibility = [];
$readOnly = [];
if ($user->role === 'Viewer') {
// Viewers can only see limited fields
$visibility['sensitiveData'] = false;
$visibility['financialInfo'] = false;
// Make all fields read-only
$readOnly['customerName'] = true;
$readOnly['email'] = true;
$readOnly['phone'] = true;
}
elseif ($user->role === 'Editor') {
// Editors can see all but can't edit sensitive data
$visibility['sensitiveData'] = true;
$visibility['financialInfo'] = true;
$readOnly['sensitiveData'] = true;
}
// Admin has full access (no restrictions)
$response['widgetsState'] = [
'visibility' => $visibility,
'readOnly' => $readOnly
];
}
onSave Event
Triggered: When form save is triggered (usually by a save button) Use For: Validate data, save to database, trigger workflows
Request Example
{
"widgetName": "form",
"widgetEvent": "onSave",
"formData": {
"customerName": "John Doe",
"email": "john@example.com"
},
"formCode": "CUSTOMERFORM",
"guid": "abc123"
}
Save Form Data with Validation
- C# / .NET
- PHP
if (widgetName == "FORM" && eventType == "ONSAVE")
{
var feCommands = (List<object>)response["feCommand"];
// Validate required fields
var errors = new List<string>();
if (string.IsNullOrEmpty(formData.GetValueOrDefault("customerName", "").ToString()))
errors.Add("Customer name is required");
if (string.IsNullOrEmpty(formData.GetValueOrDefault("email", "").ToString()))
errors.Add("Email is required");
if (errors.Any())
{
feCommands.Add(new
{
command = "ShowMessage",
args = new
{
type = "error",
message = string.Join(", ", errors)
}
});
return Ok(response);
}
var guid = requestBody.GetProperty("guid").GetString();
try
{
if (guid == "new")
{
// Create new customer
var customer = new Customer
{
Id = Guid.NewGuid(),
Name = formData["customerName"].ToString(),
Email = formData["email"].ToString(),
Phone = formData.GetValueOrDefault("phone", "").ToString(),
Address = formData.GetValueOrDefault("address", "").ToString(),
CreatedAt = DateTime.UtcNow
};
await _dbContext.Customers.AddAsync(customer);
}
else
{
// Update existing customer
var customer = await _dbContext.Customers.FindAsync(Guid.Parse(guid));
if (customer != null)
{
customer.Name = formData["customerName"].ToString();
customer.Email = formData["email"].ToString();
customer.Phone = formData.GetValueOrDefault("phone", "").ToString();
customer.Address = formData.GetValueOrDefault("address", "").ToString();
customer.UpdatedAt = DateTime.UtcNow;
_dbContext.Customers.Update(customer);
}
}
await _dbContext.SaveChangesAsync();
// Show success message
feCommands.Add(new
{
command = "ShowMessage",
args = new { type = "success", message = "Customer saved successfully!" }
});
// Close form
feCommands.Add(new
{
command = "CloseForm",
args = new { }
});
}
catch (Exception ex)
{
feCommands.Add(new
{
command = "ShowMessage",
args = new { type = "error", message = $"Error saving customer: {ex.Message}" }
});
}
}
if ($widgetName === 'FORM' && $eventType === 'ONSAVE') {
// Validate required fields
$errors = [];
if (empty($formData['customerName']))
$errors[] = 'Customer name is required';
if (empty($formData['email']))
$errors[] = 'Email is required';
if (!empty($errors)) {
$response['feCommand'][] = [
'command' => 'ShowMessage',
'args' => [
'type' => 'error',
'message' => implode(', ', $errors)
]
];
return response()->json($response);
}
$guid = $requestData['guid'];
try {
if ($guid === 'new') {
// Create new customer
$customerId = DB::table('customers')->insertGetId([
'name' => $formData['customerName'],
'email' => $formData['email'],
'phone' => $formData['phone'] ?? '',
'address' => $formData['address'] ?? '',
'created_at' => now(),
'updated_at' => now()
]);
} else {
// Update existing customer
DB::table('customers')
->where('id', $guid)
->update([
'name' => $formData['customerName'],
'email' => $formData['email'],
'phone' => $formData['phone'] ?? '',
'address' => $formData['address'] ?? '',
'updated_at' => now()
]);
}
// Show success message
$response['feCommand'][] = [
'command' => 'ShowMessage',
'args' => ['type' => 'success', 'message' => 'Customer saved successfully!']
];
// Close form
$response['feCommand'][] = [
'command' => 'CloseForm',
'args' => []
];
} catch (Exception $ex) {
$response['feCommand'][] = [
'command' => 'ShowMessage',
'args' => ['type' => 'error', 'message' => 'Error saving customer: ' . $ex->getMessage()]
];
}
}
onClose Event
Triggered: When form is about to close Use For: Clean up resources, confirm unsaved changes, log activity
Request Example
{
"widgetName": "form",
"widgetEvent": "onClose",
"formData": {
"customerName": "John Doe"
},
"formCode": "CUSTOMERFORM",
"guid": "abc123"
}
Log Form Activity
- C# / .NET
- PHP
if (widgetName == "FORM" && eventType == "ONCLOSE")
{
// Log activity
var activityLog = new ActivityLog
{
Id = Guid.NewGuid(),
UserId = requestBody.GetProperty("userId").GetString(),
FormCode = requestBody.GetProperty("formCode").GetString(),
RecordId = requestBody.GetProperty("guid").GetString(),
Action = "FormClosed",
Timestamp = DateTime.UtcNow
};
await _dbContext.ActivityLogs.AddAsync(activityLog);
await _dbContext.SaveChangesAsync();
}
if ($widgetName === 'FORM' && $eventType === 'ONCLOSE') {
// Log activity
DB::table('activity_logs')->insert([
'user_id' => $requestData['userId'],
'form_code' => $requestData['formCode'],
'record_id' => $requestData['guid'],
'action' => 'FormClosed',
'created_at' => now()
]);
}
Best Practices
- onLoad - Use for initialization only, avoid heavy computations
- onSave - Always validate data before saving
- Handle errors gracefully - Provide clear error messages to users
- Use transactions - For operations that modify multiple tables
- Log important events - Track form opens, saves, and closes for audit trails
Next Steps
- Button Events - Handle button clicks
- Datatable Events - Handle table interactions
- Frontend Commands - Control the frontend