Two approaches for field reactivity. Use either or both.
For cascading data — parent field changes, child field reloads options.
<bc-field-select name="province" options='[{"label":"Jawa Barat","value":"jabar"}]' />
<bc-field-select name="city" depend-on="province" data-source="/api/cities?province={province}" />
<bc-field-select name="district" depend-on="city" data-source="/api/districts?city={city}" />When province changes:
- City detects change via
lcFieldChangeevent - City replaces
{province}in itsdata-sourceURL with the new value - City fetches new options
- City clears its current value
- City emits its own
lcFieldChange, cascading to district
Multiple parents: depend-on="province,type" (comma-separated).
For complex logic — set values, toggle required, conditional options, cross-field validation.
BcSetup.reactivity({
'type': (value, form) => {
if (value === 'company') {
form.setRequired('tax_id', true);
form.setValue('is_company', true);
form.setOptions('salutation', [
{ label: 'PT', value: 'pt' },
{ label: 'CV', value: 'cv' }
]);
} else {
form.setRequired('tax_id', false);
form.setValue('is_company', false);
form.setOptions('salutation', [
{ label: 'Mr', value: 'mr' },
{ label: 'Mrs', value: 'mrs' }
]);
}
},
'discount': (value, form) => {
const price = form.getValue('price');
const qty = form.getValue('quantity');
form.setValue('total', Number(price) * Number(qty) * (1 - Number(value) / 100));
},
'end_date': (value, form) => {
const start = form.getValue('start_date');
if (start && value && new Date(String(value)) < new Date(String(start))) {
form.setError('end_date', 'End date must be after start date');
} else {
form.clearError('end_date');
}
}
});The form parameter in reactivity callbacks provides:
| Method | Description |
|---|---|
getValue(name) |
Get field value |
setValue(name, value) |
Set field value |
setRequired(name, bool) |
Toggle required |
setReadonly(name, bool) |
Toggle readonly |
setDisabled(name, bool) |
Toggle disabled |
setError(name, message) |
Set error message |
clearError(name) |
Clear error |
setOptions(name, options) |
Set select options |
setVisible(name, bool) |
Show/hide field |
FormProxy automatically scopes to the nearest form container — safe with multiple forms on one page.
Reactivity rules are scoped to the nearest form container:
<form>element<bc-view-form>component- Element with
data-bc-formattribute
This prevents cross-form interference when multiple forms exist on one page.
Field emits lcFieldChange
↓
1. Declarative: sibling with depend-on="thisField" re-fetches data
↓
2. Imperative: BcSetup.reactivity rule for this field executes
↓
3. FormEngine (if present): depends_on, readonly_if, mandatory_if, formula
All three can coexist. Declarative and imperative are standalone. FormEngine is BitCode-specific.