OnLookup & OnValidate #2

Although you might be aware now that any code in the OnLookup trigger will leave you as a developer to handle everything yourself, you have made the choice to write your own lookup functionality. As mentioned in my previous post OnLookup & OnValidate #1, you not only need to program the look up itself but also have to take care that the selected value is handed over to the field from where the user will perform the lookup, including its validation. Well ... except in the case of programming your lookup code on the relevant form control (see below).

Validation Schema

So what exactly does a developer need to take care of when needing to program lookup functionality?

Before we dive into that it’s worthwhile to read this section from the manual of our former "Programming in C/AL" course:

Some application objects have similar triggers, likewise the OnValidate trigger, which exists on tables as field trigger(s) or on forms as control trigger(s). When, after a user action, a value will be validated Attain will execute (in this order)

  • system validation, i.e. checking the value against properties
  • field OnValidate trigger (if coded)
  • control OnValidate trigger (if coded)

The OnLookup trigger also exists as field and control trigger. The execution plan, however, is totally different.

  • If no code has been implemented in either of the OnLookup triggers, the standard (system) look up will be performed
  • If code has been implemented in both Onlookup triggers the control trigger will only be executed
  • If only the field OnLookup trigger contains code the field trigger code will be executed

Based on this it’s interesting to do some investigations into the validation schema when performing each of the lookups given the fact that both at field and control level the OnValidate trigger has been populated.

Standard Lookup

When executing a standard lookup the 3 validation levels are executed in this order:

  1. System Validation (TableRelation!)
  2. Field - OnValidate
  3. Control - OnValidate

Field Lookup

Executing a lookup programmed at field level only 2 validation levels are executed in this order:

  1. System Validation
  2. Field - OnValidate, if explicitly programmed!

No control OnValidate!

Control Lookup

And last but not least, when a lookup has been implemented on the control again 3 levels of validation are triggered (and executed):

  1. System Validation
  2. Field - OnValidate (does not need to be called explicitly; see below)
  3. Control - OnValidate

OnLookup at Field Level

The code should consist of 3 steps:

  1. Set the current value (this will make sure the current value is selected when the form is opened)
  2. Look up the new value
  3. Validate the value (using the field's OnValidate trigger)

Example

Customer No. - OnLookup()
Customer."No." := "Customer No.";
IF FORM.RUNMODAL(0,Customer) = ACTION::LookupOK THEN
  VALIDATE("Customer No.",Customer."No.");

OnLookup at Control Level

The code should consist of 4 steps:

  1. Set the current value (this will make sure the current value is selected when the form is opened)
  2. Look up the new value
  3. Assign the new value to the variable (parameter!) Text
  4. Return TRUE if the lookup was successful

Example

Customer No. - OnLookup(VAR Text : Text[1024];) : Boolean
Customer."No." := "Customer No.";
IF FORM.RUNMODAL(0,Customer) = ACTION::LookupOK THEN BEGIN
  Text := FORMAT(Customer."No.");
  EXIT(TRUE);
END;

Notes

  • Unlike with the field trigger there is no need to validate the values returned. This is handled by the system because the OnValidate and OnAfterValidate triggers are called.
  • This method can also be used for lookups on controls that have a variable as source expression (on a request form for example). By passing the value to the variable Text you ensure that the OnValidate and OnAfterValidate triggers of the control are called and you do not need to duplicate validation code. Preferably you would put the validation code and the lookup code in functions so the code can be reused (see below).

SMART Programming

Implement your lookup feature as one function on your table so that you can reuse the same function for the OnLookup triggers on the field and control(s).

On the table (field) you could have the following code

Customer No. - OnValidate()
// Update some other record(s) in the same table. This will require a form refresh

Customer No. - OnLookup()
VALIDATE("Customer No.",LookupCustomerNo("Customer No."));

LookupCustomerNo(CurrCustNo : Code[20]) : Code[20]
Customer."No." := CurrCustNo;
IF FORM.RUNMODAL(0,Customer) = ACTION::LookupOK THEN
  EXIT(Customer."No.");

On the form (control) you would have the following code:

Customer No. - OnAfterValidate()
CurrForm.UPDATE(FALSE);

<Control1000000> - OnLookup(VAR Text : Text[1024];) : Boolean
Text := FORMAT(LookupCustomerNo("Customer No."));
EXIT(Text <> '');

Notes

  • In our example there is no need to explicitly add the FORMAT since type Code is automatically converted to type Text. However It is needed for other variable types.
  • Add a CurrForm.UPDATE(FALSE) to the OnAfterValidate trigger on the control.
  • Everything also applies to pages.

Muchas Gracias to ...

... my good old ex-colleague Gert Robyns (MSFT). Cheers, pal! Beer

Anonymous
Related
Recommended