C/AL includes a number of utility functions designed to facilitate data validation or initialization. Some of these functions are:
TESTFIELD
FIELDERROR
INIT
VALIDATE
The TESTFIELD
function is widely used in standard NAV code. With TESTFIELD
, we can test a variable value and generate an error message in a single statement if the test fails. The syntax is:
Record.TESTFIELD (Field, [Value] )
If a Value
is specified and the field does not contain that value, the process terminates with an error condition and the error message is issued.
If no Value
is specified, the field contents are checked for values of zero or blank. If the field is zero or blank, then that an error message is issued.
The advantage of TESTFIELD
is the ease of use and consistency in the code and the message displayed. The disadvantage is that the error message is not as informative as we might provide as a careful developer.
The following screenshot of TESTFIELD
usage is from Table 18 – Customer. This code checks to make sure that the Sales Order field Status
is equal to the option value Open
before allowing the value of the field "Sell-to Customer No."
to be entered.
TESTFIELD(State,Status::Open);
An example of the error message generated when attempting to change the "Sell-to Customer No."
when Status
is not equal to the option value Open
, is as follows:
Another function very similar to the TESTFIELD
function is FIELDERROR
. But where TESTFIELD
performs a test and terminates with either an error or an OK result, FIELDERROR
presumes that the test was already performed and the field failed the test. FIELDERROR
is designed to display an error message, then terminate the process. This approach is followed in much of the NAV logic, especially in the Posting Codeunits (for example, Codeunits 12, 80, 90). The syntax is as follows:
TableName.FIELDERROR(FieldName[,OptionalMsgText]);
If we include our own message text by defining a Text Constant in the C/AL Globals | Text Constants tab (so the code can be multilingual), we will have:
Text001 must be greater than Start Time
Then we can reference the Text Constant in code:
IF Rec."End Time" <= "Start Time" THEN Rec.FIELDERROR("End Time",Text001);
The result is an error message from FIELDERROR
like that shown in the following screenshot:
An error message that simply identifies the data field, but does not reference a message text, looks like the following screenshot, with the record key information displayed:
Because the error message begins with the name of the field, we need to be careful that our Text Constant is structured to make the resulting error message easy to read.
If we don't include our own message text, the default message comes in two flavors. The first instance is the case where the referenced field is not empty. Then the error message presumes that the error is due to a wrong value, as shown in the previous image. In the case where the referenced data field is empty, the error message logic presumes the field should not be empty, as shown in the following image:
The INIT
function initializes a record in preparation for its use, typically in the course of building a record entry to insert in a table. The syntax is:
Record.INIT;
All the data fields in the record are initialized as follows:
InitValue
property are initialized to the specified value.InitValue
are initialized to the default value for their data type.The syntax of the VALIDATE
function is as follows:
Record.VALIDATE ( Field [, Value] )
VALIDATE
will fire the OnValidate
trigger of Record.Field
. If we have specified a Value
, that Value
is assigned to the field and the field validations are invoked.
If we don't specify a Value
, then the field validations are invoked using the field value that already exists in the field. This function allows us to easily centralize our code design around the table, which is one of NAV's strengths.
For example, if we were to code changing Item."Base Unit of Measure"
to another unit of measure, the code should make sure the change is valid. We should get an error if the new unit of measure has any quantity other than 1 (because that is a requirement of the Base Unit of Measurement field). Making the unit of measure change with a simple assignment statement would not catch a quantity error.
Following are the two forms of using VALIDATE
which give the same end result:
Item.VALIDATE("Base Unit of Measure",'Box'),
Item."Base Unit of Measure" := 'Box';
Item.VALIDATE("Base Unit of Measure");