BC AL Journey #10
Creating data elements, displaying and manipulating that data is a critical part of a Business Central customization. In many implementations simply storing the data is not enough, we need to act and react to data inputs into the system. This is where Triggers and Events come into play.
Thus far on our journey we have been working in the definition language of Business Central AL. The language we have used defines tables, pages, data sets, reports, permissions, and a few other things. There is another language that is used to perform work, the programming language.
The programming language of AL is based on Pascal and is a block structured language. One of the challenges all Business Central AL developers face is switching between the definition and programming languages. The good news is that Visual Studio Code has excellent support for this duplicity.
To ease into this, we are going to start with Table and Page triggers. In Business Central triggers serve as events that we can tap into to do work when the user performs an action. A very common trigger is the OnValidate trigger, which happens anytime a field is edited.
Some triggers, in our case OnValidate, can exist on both the table and page. Choosing if the trigger should be applied to a table or page depend on the purpose of the trigger. If it is on the page, then the trigger only happens when that page is used, and we can have multiple pages referencing the same table. If the trigger is on the table, then it happens regardless of what page is used. Another way to look at it is that pages allow for audience specific rules, while tables enforce a single ruleset for everyone.
Remember APIs are a special case Pages and the rules we apply at the table level will impact external access. Triggers that prompt the user for input or notify of data errors won’t be applicable with API calls.
Let’s get into some code!
Use Case
User would like to ensure that all data entered into the weights and measurement fields of the item card is not less than zero.
Implementation
- Add OnValidate triggers to the following fields:
- ARD_Length
- ARD_Width
- ARD_Height
- ARD_Weight
- Validate that the user input is not less than zero
Test Plan
- For each field enter a value less than zero
- Verify Error Message
- For each field enter a value greater than or equal to 0
- Verify that there is no error message
To implement this customization, we are going to edit the ARDItem.TableExt.AL that we created in BC AL Journey #4. We are going to add the OnValidate trigger to each of the listed fields with a test and an error message. Let’s look at the code for the ARD_Length field.
field(50001; ARD_Length; Decimal)
{
Caption = 'Length';
DataClassification = CustomerContent;
ToolTip = 'Item Length';
trigger OnValidate()
var
ErrMsg: Label 'Length must be greater than zero.';
begin
if Rec.ARD_Length < 0 then
Error(ErrMsg);
end;
}
We start inside the { } defined scope for the field for ARD_Length. You can see I’ve added a trigger OnValidate(). From here we are in a more Pascal like language. Let’s break down the anatomy of this trigger.
The first line is the trigger definition, it is the “On What” statement that defines when the trigger will execute. The second thing is the key word “var”, this flags the variables that will be used inside the trigger. All variables, except global variables, must be defined in the var section. We will cover global variables later, right now it is best to keep your variables scoped to the trigger.
Directly after the var is a begin statement and further down an end statement. These set the scope of the trigger, similar to how we scope the field definition with a { and }. The entire block ends with a “;” indicating the end of the trigger.
Inside the trigger you can see we have a variable of a Label called ErrMsg and a static text of the message we want the user to see. We define variables with a “Name: Type;” format. Some variables like a Label require you to set the value when you define them.
We use a label here because they support multilanguage translations. Implementing multiple languages is a challenge for another day but know that you could pass a string to the Error method we use, however it would not support the language tools built into BC.
Working with labels – Business Central | Microsoft Learn
The test condition inside the trigger is about as simple as it can be. Test if the value in the field is less than zero. We use the system defined variable “Rec” which contains the current record value, check if it is less than zero, and if it is use the Error procedure to show the error message.
There are several system defined variables that are “free” based on the type of object you are working with. Rec is the current record, and xRec is the previous record state before the validate was called. We don’t need to define these, they simply exist.
We use an If <test> then method. As this is a single line we don’t need to provide a scope, but if it were multiple lines, we would enclose the code with a begin and end; scope. It is Business Central AL code best practice to not begin/end scope a single line statement.
We can apply this logic to the other fields in the table extension and test out the results. If you are cutting and pasting, remember to change the label text and the field in the test condition. You can also see the code in the GitHub repo.

Setting the length to a negative number generates the error message and entering a number 0 or greater will not generate an error and clear an existing error.
With that tested and validated we have completed our first dive into triggers. There are a lot of triggers available, and they exist in all of the objects within Business Central.
Triggers overview – Business Central | Microsoft Learn
We will see more triggers as we perform more data validation and other data handling routines in the future. We will also expand further on triggers and data processing as we move into procedures and other programming concepts.






Leave a reply to Essential Triggers for Record Management in AL Programming – Aardvark Labs Cancel reply