Event types
Events are a way to provide a way for one piece of code to communicate with another. In Business Central, events are used to notify other objects that something has occurred. This can be useful when you want to notify other objects that something has happened, or when you want to allow other objects to influence the behavior of your code. Business Central supports different types of events including BusinessEvents, IntegrationEvents, Global events, and trigger events.
Business events
A business event is a custom event that is raised by AL code. It defines a formal contract that carries an implicit promise not to change in future releases. It's the expectation that business events are published by solution ISVs, including Microsoft.
Business events can be compared with publicly released APIs on which third party solution providers develop integrations and additions. Therefore, the downstream cost of making changes to a business event implementation can be considerable for those who use the event in their applications. There may be some cases where changes are required; however, you should keep these to an absolute minimum.
Development considerations
A typical business event reflects changes in “state” with regard to a process. This makes them well suited for workflow. An example of a business event could be when a sales order has been posted. It's important to note that business events shouldn't be tied to the implementation-details, such as the tables or fields in which the data is stored. Preferably, the event publisher developer should be free to change the implementation, while still keeping the business event intact. To learn about the syntax and example on how to use the BusinessEvent type, see BusinessEvent Attribute.
Business events should be documented with the solution, including the before-state and after-state of the events.
Integration events
An integration event is also a custom event that is raised by AL code, like a business event, except that it does not carry the same promise of not changing, nor does it have the restriction not to expose implementation details.
The main purpose of integration events is to enable the integration of other solutions with Dynamics 365 Business Central without having to perform traditional code modifications.
Development considerations
An integration event can be changed to a business event later. At which time, it must adhere to the same implied contract and commitment as any business event. It can also simply be designed-in hook points for external add-ons. To learn about the syntax and example on how to use the IntegrationEvent type, see IntegrationEvent attribute.
Development considerations
To learn about the syntax and example on how to use the InternalEvent type, see InternalEvent attribute.
Global events
Global events are predefined system events that are automatically raised by various base application codeunits. For example, codeunit 40 LoginManagement includes several global method triggers, such as CompanyOpen, CompanyClose, and GetSystemIndicator. For most of these global method triggers, there are one or two global events: a before and after event. For example, there is an OnBeforeCompanyOpen event and an OnAfterCompanyOpen event. The global events are defined as integration event publishers by local methods in the following codeunits.
Codeunit ID | Codeunit Name | Event |
---|---|---|
9170 | Conf./Personalization Mgt. | OnRoleCenterOpen |
OnAfterLogInEnd | ||
OnBeforeLogInStart | ||
OnBeforeCompanyOpen | ||
OnAfterCompanyOpen | ||
OnBeforeCompanyClose | ||
OnAfterCompanyClose | ||
42 | TextManagement | OnBeforeMakeTextFilter |
OnAfterMakeDateTimeFilter | ||
OnAfterMakeDateFilter | ||
OnAfterMakeTextFilter | ||
OnAfterMakeTimeFilter | ||
42* | Caption Class | OnAfterCaptionClassResolve |
OnResolveCaptionClass | ||
44 | ReportManagement | OnAfterGetPrinterName |
OnAfterDocumentPrintReady | ||
OnAfterGetPaperTrayForReport | ||
OnAfterGetPrinterName | ||
OnAfterHasCustomLayout | ||
OnAfterDocumentReady | ||
OnAfterIntermediateDocumentReady | ||
OnAfterDocumentDownload | ||
OnAfterSetupPrinters | ||
OnCustomDocumentMergerex | ||
OnAfterSubstituteReport | ||
45 | AutoFormatManagement | OnAfterAutoFormatTranslate |
49 | GlobalTriggerManagement | OnAfterGetGlobalTableTriggerMask |
OnAfterOnGlobalInsert | ||
OnAfterOnGlobalModify | ||
OnAfterOnGlobalDelete | ||
OnAfterOnGlobalRename | ||
OnAfterGetDatabaseTableTriggerSetup | ||
OnAfterOnDatabaseInsert | ||
OnAfterOnDatabaseModify | ||
OnAfterOnDatabaseDelete | ||
OnAfterOnDatabaseRename | ||
OnBeforeOnDatabaseInsert | ||
OnBeforeOnDatabaseModify | ||
OnBeforeOnDatabaseDelete | ||
OnBeforeOnDatabaseRename |
* Codunit 42 Caption Class was introduced as a replacement for codeunit 42 CaptionManagement. In previous versions, codeunit 42 CaptionManagement included the OnAfterCaptionClassTranslate
event. For more information, see Breaking Changes in the legacy ALAppExtensions GitHub repo.
Trigger events
Unlike business and integration events which must be programmed, trigger events are predefined events. Trigger events are published by the runtime and they cannot be raised programmatically. There are two types of trigger events: database trigger events and page trigger events.
Note
Trigger events don't appear as methods in AL for a table or page object.
Database trigger events
Trigger events are automatically raised by the system when it performs database operations on a table object, such as deleting, inserting, modifying, and renaming a record, as defined in a table. Trigger events are closely associated with the table triggers for database operations: OnDelete, OnInsert, OnModify, OnRename, and OnValidate (for fields). For each database operation, there is a "before" and "after" trigger event with a fixed signature.
Available database trigger events
The following table describes the available database trigger events:
Database trigger event | Signature | Description |
---|---|---|
OnAfterDeleteEvent Trigger Event | [EventSubscriber(ObjectType::Table, Database::<Table Name>, 'OnAfterDeleteEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record; RunTrigger: Boolean) |
Executed after a record is deleted from a table. |
OnAfterInsertEvent Trigger Event | [EventSubscriber(ObjectType::Table, Database::<Table Name>, 'OnAfterInsertEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record; RunTrigger: Boolean) |
Executed after a record is inserted in a table. |
OnAfterModifyEvent Trigger Event | [EventSubscriber(ObjectType::Table, Database::<Table Name>, 'OnAfterModifyEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] procedure MyProcedure(var Rec: Record; var xRec: Record; RunTrigger: Boolean) |
Executed after a record is modified in a table. |
OnAfterRenameEvent Trigger Event | [EventSubscriber(ObjectType::Table, Database::<Table Name>, 'OnAfterRenameEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] procedure MyProcedure(var Rec: Record; var xRec: Record; RunTrigger: Boolean) |
Executed after a record is renamed in a table. |
OnAfterValidateEvent Trigger Event | [EventSubscriber(ObjectType::Table, Database::<Table Name>, 'OnAfterValidateEvent', '<Field Name>', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] procedure MyProcedure(var Rec: Record; var xRec: Record; CurrFieldNo: Integer) |
Executed after a field is validated when its value has been changed. |
OnBeforeDeleteEvent Trigger Event | [EventSubscriber(ObjectType::Table, Database::<Table Name>, 'OnBeforeDeleteEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] procedure MyProcedure(var Rec: Record; RunTrigger: Boolean) |
Executed before a record is deleted from a table. |
OnBeforeInsertEvent Trigger Event | [EventSubscriber(ObjectType::Table, Database::<Table Name>, 'OnBeforeInsertEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] procedure MyProcedure(var Rec: Record; RunTrigger: Boolean) |
Executed before a record is inserted in a table. |
OnBeforeModifyEvent Trigger Event | [EventSubscriber(ObjectType::Table, Database::<Table Name>, 'OnBeforeModifyEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] procedure MyProcedure(var Rec: Record; var xRec: Record; RunTrigger: Boolean) |
Executed before a record is modified in a table. |
OnBeforeRenameEvent Trigger Event | [EventSubscriber(ObjectType::Table, Database::<Table Name>, 'OnBeforeRenameEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] procedure MyProcedure(var Rec: Record; var xRec: Record; RunTrigger: Boolean) |
Executed before a record is renamed in a table. |
OnBeforeValidateEvent Trigger Event | [EventSubscriber(ObjectType::Table, Database::<Table Name>, 'OnBeforeValidateEvent', '<Field Name>', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] procedure MyProcedure(var Rec: Record; var xRec: Record; CurrFieldNo: Integer) |
Executed before a field is validated when its value has been changed. |
The following table describes the parameters of the trigger events:
Parameter | Type | Description |
---|---|---|
Rec | Record | The table that raises the event. |
xRec | Record | The table that raises the event. |
RunTrigger | Boolean | Specifies whether to execute the code in the event trigger when it is invoked. If this parameter is true, the code will be executed. If this parameter is false, then the code is not executed. |
CurrFieldNo | Integer | The number of the field that raises the event. |
Order of event execution
The relative order of execution of database trigger events, table triggers, and database operations is as follows:
Order | Item | Example |
---|---|---|
1 | Trigger event (before) | OnBeforeDeleteEvent |
2 | Table trigger | OnDelete |
3 | Global table trigger in codeunit | OnDatabaseDelete |
4 | Database operations | Delete the record |
5 | Trigger event (after) | OnAfterDeleteEvent |
Page trigger events
Page trigger events are raised automatically by the system when it performs certain operations in a page object. Page trigger events are closely associated with the standard page triggers, such as OnOpenPage, OnClosePage, and OnAction.
Available page trigger events
The following table describes the available page trigger events:
Trigger event | Signature | Description |
---|---|---|
OnAfterActionEvent Trigger Event | [EventSubscriber(ObjectType::Page, Page::<Page Name>, 'OnAfterActionEvent', '<Action Name>', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record) |
Executed after the OnAction trigger, which is called when a user selects an action on the page. |
OnAfterGetCurrRecordEvent Trigger Event | [EventSubscriber(ObjectType::Page, Page::<Page Name>, 'OnAfterGetCurrRecordEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record) |
Executed after the OnAfterGetCurrRecord trigger, which is called after the current record is retrieved from the table. |
OnAfterGetRecordEvent Trigger Event | [EventSubscriber(ObjectType::Page, Page::<Page Name>, 'OnAfterGetRecordEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record) |
Executed after the OnAfterGetCurrRecord trigger, which is called after the record is retrieved from the table but before it is displayed to the user. |
OnAfterValidateEvent Trigger Event | [EventSubscriber(ObjectType::Page, Page::<Page Name>, 'OnAfterValidateEvent', '<Control Name>', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record; var xRec: Record) |
Executed after the OnValidate (Page fields) trigger, which is called when a field loses focus after its value has been changed. |
OnBeforeActionEvent Trigger Event | [EventSubscriber(ObjectType::Page, Page::<Page Name>, 'OnBeforeActionEvent', '<Action Name>', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record) |
Executed before the OnAction trigger, which is called when a user selects an action on the page. |
OnBeforeValidateEvent Trigger Event | [EventSubscriber(ObjectType::Page, Page::<Page Name>, 'OnBeforeValidateEvent', '<Control Name>', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record; var xRec: Record) |
Executed before the OnValidate (Page fields) trigger, which is called when a field loses focus after its value has been changed. |
OnClosePageEvent Trigger Event | [EventSubscriber(ObjectType::Page, Page::<Page Name>, 'OnClosePageEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record) |
Executed after the OnClosePage trigger, which is called when page closes after the OnQueryClosePage trigger is executed. |
OnDeleteRecordEvent Trigger Event | [EventSubscriber(ObjectType::Page, Page::<Page Name>, 'OnDeleteRecordEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record; var AllowDelete: Boolean) |
Executed after the OnDeleteRecord trigger, which is called before a record is deleted from a table. |
OnInsertRecordEvent Trigger Event | [EventSubscriber(ObjectType::Page, Page::<Page Name>, 'OnInsertRecordEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record; BelowxRec: Boolean; var xRec: Record; var AllowInsert: Boolean) |
Executed after the OnInsertRecord trigger, which is called before a record is inserted in a table. |
OnModifyRecordEvent Trigger Event | [EventSubscriber(ObjectType::Page, Page::<Page Name>, 'OnModifyRecordEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record; var xRec: Record; var AllowModify: Boolean) |
Executed after the OnModifyRecord trigger, which is called before a record is modified in a table. |
OnNewRecordEvent Trigger Event | [EventSubscriber(ObjectType::Page, Page::<Page Name>, 'OnNewRecordEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record; BelowxRec: Boolean; var xRec: Record) |
Executed after the OnNewRecord trigger, which is called before a new record is initialized. |
OnOpenPageEvent Trigger Event | [EventSubscriber(ObjectType::Page, Page::<Page Name>, 'OnOpenPageEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record) |
Executed after the OnOpenPage trigger, which is called after a page is initialized and run. |
OnQueryClosePageEvent Trigger Event | [EventSubscriber(ObjectType::Page, Page::<Page Name>, 'OnQueryClosePageEvent', '', <SkipOnMissingLicense>, <SkipOnMissingPermission>)] local procedure MyProcedure(var Rec: Record; var AllowClose: Boolean) |
Executed after the OnQueryClosePage trigger, which is called as a page closes and before the OnClosePage trigger executes. |
The following table describes the parameters of the trigger events:
Parameter | Type | Description |
---|---|---|
Rec | Record | The table that used page that raises the event. |
xRec | Record | The table that used page that raises the event. |
AllowDelete | Boolean | Specifies whether the OnDeleteRecord trigger call was successful and the record can be deleted. If this parameter is true, the code will be executed. If this parameter is false, then the code is not executed. |
AllowModify | Boolean | Specifies whether the OnModifyRecord trigger call was successful and the record can be modified. If this parameter is true, the code will be executed. If this parameter is false, then the code is not executed. |
BelowxRec | Boolean | Specifies whether the new record was inserted after the last record in the table (xRec). |
AllowClose | Boolean | Specifies whether to the page can close. If this parameter is true, the code will be executed. If this parameter is false, then the code is not executed. |
Related information
Events in AL
Publishing events
Raising events
Subscribing to events
Isolated events