Skip to main content

Field Change Events

Field change events trigger when a user modifies field values. Use these to calculate dependent values, validate input, or load related data.

Event Types

Events: onChange, onBlur, onFocus

EventTriggered When
onChangeField value changes
onBlurField loses focus
onFocusField receives focus

Request Example

{
"widgetName": "quantity",
"widgetEvent": "onChange",
"widgetValue": "5",
"formData": {
"quantity": "5",
"unitPrice": "100.00",
"totalPrice": "0"
},
"formCode": "ORDERFORM",
"guid": "new"
}

Common Use Cases

Calculate Dependent Fields

if (widgetName == "QUANTITY" && eventType == "ONCHANGE")
{
// Calculate total price when quantity changes
if (decimal.TryParse(formData.GetValueOrDefault("quantity", "0").ToString(), out var quantity) &&
decimal.TryParse(formData.GetValueOrDefault("unitPrice", "0").ToString(), out var unitPrice))
{
var totalPrice = quantity * unitPrice;
formData["totalPrice"] = totalPrice.ToString("F2");
response["formData"] = formData;
}
}
else if (widgetName == "UNITPRICE" && eventType == "ONCHANGE")
{
// Calculate total price when unit price changes
if (decimal.TryParse(formData.GetValueOrDefault("quantity", "0").ToString(), out var quantity) &&
decimal.TryParse(formData.GetValueOrDefault("unitPrice", "0").ToString(), out var unitPrice))
{
var totalPrice = quantity * unitPrice;
formData["totalPrice"] = totalPrice.ToString("F2");
response["formData"] = formData;
}
}
if (widgetName == "CUSTOMERID" && eventType == "ONCHANGE")
{
// Load customer details when customer is selected
var customerId = formData.GetValueOrDefault("customerId", "").ToString();

if (!string.IsNullOrEmpty(customerId))
{
var customer = await _dbContext.Customers
.FirstOrDefaultAsync(c => c.Id.ToString() == customerId);

if (customer != null)
{
// Prefill customer details
formData["customerName"] = customer.Name;
formData["email"] = customer.Email;
formData["phone"] = customer.Phone;
formData["address"] = customer.Address;
response["formData"] = formData;

// Load customer's orders in a datatable
var orders = await _dbContext.Orders
.Where(o => o.CustomerId.ToString() == customerId)
.Select(o => new Dictionary<string, string>
{
{ "_id", o.Id.ToString() },
{ "_sk", o.Id.ToString() },
{ "_code", "ORDER" },
{ "orderNumber", o.OrderNumber },
{ "orderDate", o.OrderDate.ToString("yyyy-MM-dd") },
{ "total", o.Total.ToString("F2") }
})
.ToListAsync();

response["widgetData"] = orders;
}
}
}

Validate Input

if (widgetName == "EMAIL" && eventType == "ONBLUR")
{
var feCommands = (List<object>)response["feCommand"];
var email = formData.GetValueOrDefault("email", "").ToString();

// Validate email format
if (!string.IsNullOrEmpty(email) && !IsValidEmail(email))
{
feCommands.Add(new
{
command = "ShowMessage",
args = new
{
type = "error",
message = "Please enter a valid email address"
}
});

// Clear invalid email
formData["email"] = "";
response["formData"] = formData;
}
}

// Helper method
private bool IsValidEmail(string email)
{
try
{
var addr = new System.Net.Mail.MailAddress(email);
return addr.Address == email;
}
catch
{
return false;
}
}

Dynamic Dropdown Cascade

if (widgetName == "COUNTRY" && eventType == "ONCHANGE")
{
// Load cities based on selected country
var countryId = formData.GetValueOrDefault("country", "").ToString();

if (!string.IsNullOrEmpty(countryId))
{
var cities = await _dbContext.Cities
.Where(c => c.CountryId.ToString() == countryId)
.ToDictionaryAsync(
c => c.Id.ToString(),
c => c.Name
);

response["fieldAllowedValues"] = new Dictionary<string, object>
{
{ "city", cities }
};

// Clear previously selected city
formData["city"] = "";
response["formData"] = formData;
}
}
else if (widgetName == "CITY" && eventType == "ONCHANGE")
{
// Load districts based on selected city
var cityId = formData.GetValueOrDefault("city", "").ToString();

if (!string.IsNullOrEmpty(cityId))
{
var districts = await _dbContext.Districts
.Where(d => d.CityId.ToString() == cityId)
.ToDictionaryAsync(
d => d.Id.ToString(),
d => d.Name
);

response["fieldAllowedValues"] = new Dictionary<string, object>
{
{ "district", districts }
};

// Clear previously selected district
formData["district"] = "";
response["formData"] = formData;
}
}

Show/Hide Fields Based on Value

if (widgetName == "CUSTOMERTYPE" && eventType == "ONCHANGE")
{
var customerType = formData.GetValueOrDefault("customerType", "").ToString();

if (customerType == "company")
{
// Show company-specific fields
response["widgetsState"] = new
{
visibility = new Dictionary<string, bool>
{
{ "companyName", true },
{ "taxNumber", true },
{ "vatNumber", true },
{ "firstName", false },
{ "lastName", false }
},
readOnly = new Dictionary<string, bool>()
};
}
else if (customerType == "individual")
{
// Show individual-specific fields
response["widgetsState"] = new
{
visibility = new Dictionary<string, bool>
{
{ "companyName", false },
{ "taxNumber", false },
{ "vatNumber", false },
{ "firstName", true },
{ "lastName", true }
},
readOnly = new Dictionary<string, bool>()
};
}
}

Apply Discount Based on Input

if (widgetName == "DISCOUNTCODE" && eventType == "ONCHANGE")
{
var feCommands = (List<object>)response["feCommand"];
var discountCode = formData.GetValueOrDefault("discountCode", "").ToString();

// Validate discount code
var discount = await _dbContext.DiscountCodes
.FirstOrDefaultAsync(d => d.Code == discountCode && d.IsActive);

if (discount != null)
{
// Apply discount
formData["discountPercent"] = discount.Percentage.ToString();

// Recalculate total
if (decimal.TryParse(formData.GetValueOrDefault("subtotal", "0").ToString(), out var subtotal))
{
var discountAmount = subtotal * (discount.Percentage / 100m);
var total = subtotal - discountAmount;

formData["discountAmount"] = discountAmount.ToString("F2");
formData["total"] = total.ToString("F2");
}

response["formData"] = formData;

feCommands.Add(new
{
command = "ShowMessage",
args = new
{
type = "success",
message = $"Discount code applied: {discount.Percentage}% off"
}
});
}
else if (!string.IsNullOrEmpty(discountCode))
{
feCommands.Add(new
{
command = "ShowMessage",
args = new
{
type = "error",
message = "Invalid discount code"
}
});

formData["discountCode"] = "";
formData["discountPercent"] = "0";
formData["discountAmount"] = "0";
response["formData"] = formData;
}
}

Best Practices

  1. Debounce expensive operations - For operations like database lookups, consider implementing debouncing on the frontend
  2. Validate on blur - Use onBlur for validation to avoid interrupting the user while typing
  3. Provide immediate feedback - Use onChange for real-time calculations
  4. Clear dependent fields - When a parent field changes, clear dependent child fields
  5. Handle empty values - Always check for null/empty values before processing

Next Steps