Skip to main content

Form Code Extensions

Chain of Command (CoC) allows you to wrap existing form methods — executing logic before and after the original method — without modifying the base code. Form CoC is more granular than table CoC because forms have three distinct extension targets: the form itself, its data sources, and individual data source fields.

Form-Level CoC

Target the form using [ExtensionOf(formStr(FormName))].

[ExtensionOf(formStr(SalesTable))]
final class SAMOSalesTable_Form_Extension
{
public void init()
{
// Pre-init logic
next init();
// Post-init logic

FormRun formRun = this as FormRun;
FormControl myControl = formRun.design().controlName('SAMOCustomControl');
}

public void close()
{
// Pre-close logic
next close();
}
}

Wrappable Form Methods

MethodDescription
init()Form initialisation — add ranges, set up state.
run()Executes after init() — the form is visible.
close()Form is closing — cleanup, refresh caller.
canClose()Determines if the form can close (return false to prevent).
task(int)Intercept form tasks (keyboard shortcuts, menu commands).

Data Source CoC

Target a specific data source using [ExtensionOf(formDataSourceStr(FormName, DataSourceName))].

[ExtensionOf(formDataSourceStr(SalesTable, SalesTable))]
final class SAMOSalesTableDS_Extension
{
public void init()
{
next init();

// Add a filter range after data source initialisation
this.query().dataSourceTable(tableNum(SalesTable))
.addRange(fieldNum(SalesTable, SalesStatus))
.value(queryValue(SalesStatus::Invoiced));
}

public void executeQuery()
{
// Modify query before execution
next executeQuery();
// Post-query logic
}

public int active()
{
int ret = next active();

// Enable/disable controls based on current record
SalesTable salesTable = this.cursor();
FormRun formRun = this.formRun();
formRun.design().controlName('SAMOPostButton')
.enabled(salesTable.SalesStatus == SalesStatus::Backorder);

return ret;
}
}

Wrappable Data Source Methods

MethodDescription
init()Data source initialisation — add ranges, configure query.
executeQuery()Refresh data — modify ranges before next, react to results after.
active()Current record changed — enable/disable controls.
validateWrite()Validate before save.
validateDelete()Validate before delete.
write()Record save operation.
create()New record creation.
delete()Record deletion.
initValue()Set default values for new records.

Data Source Field CoC

Target a specific field using [ExtensionOf(formDataFieldStr(FormName, DataSourceName, FieldName))].

[ExtensionOf(formDataFieldStr(SalesTable, SalesTable, SalesId))]
final class SAMOSalesId_Field_Extension
{
public void modified()
{
next modified();

// React to SalesId field change
FormDataSource fds = this.datasource();
SalesTable salesTable = fds.cursor();
// Lookup related data
}

public boolean validate()
{
boolean ret = next validate();

if (ret)
{
// Additional field validation
}

return ret;
}
}

Wrappable Field Methods

MethodDescription
modified()Field value changed — cascade updates.
validate()Field validation — return false to reject the value.
lookup()Custom lookup — override the dropdown list.
jumpRef()Go-to-main-table navigation.

Naming Conventions

TargetPatternExample
Form extension class<Prefix><FormName>_Form_ExtensionSAMOSalesTable_Form_Extension
Data source class<Prefix><FormName><DS>_ExtensionSAMOSalesTableDS_Extension
Field class<Prefix><FieldName>_Field_ExtensionSAMOSalesId_Field_Extension

CoC Rules

  1. Always call next. Every wrapped method must call next exactly once.
  2. Classes must be final. The compiler enforces this.
  3. No constructors or state fields. Extension classes share the form's scope.
  4. Method signatures must match exactly. Same name, return type, and parameters as the base method.
  5. Access level cannot be more restrictive than the original method.
tip

Choose CoC vs Event Handlers:

  • Use CoC when you need to modify parameters, return values, or execution flow (e.g., adding ranges before super(), altering validation results).
  • Use event handlers when you need to respond to a lifecycle moment without modifying behaviour (e.g., post-init setup, logging).