Skip to main content

Accessing the value of an EntityField

This chapter is about the relation between the value of an EntityField and its associated variables.

note

In this chapter, "value of an EntityField" is actually referring to a specific value processed in the ADITO core. For a better understanding of the following explanations, you can simply consider "value of an EntityField" to be the value that is visible in the client.

If you have created an EntityField called MYFIELD, then it automatically has a system variable with the name $field.MYFIELD associated. You can access the value of this variable via the method vars.get("$field.MYFIELD").

The EntityField value and the $field variable value are linked in the ADITO core. Each is calculated at different times, and at certain points they are synchronized to each other.

Synchronization

There are two ways of synchronizing:

  1. EntityField value -> $field variable value
    If the value of an EntityField is set, then it triggers a new calculation of the variable.
  2. $field variable value -> EntityField value
    If the value of the $field variable changes, its value gets set to the EntityField value.

How does an EntityField value get set?

The value of an EntityField is set, when a user enters a value in a View. This is when the new calculation of the variable is triggered according to the execution order of processes, see chapter Execution Order of Entity Processes.

How does a "$field" variable get its value?

There are three variants of how the value of a $field variable can be determined:

  1. Record
    If you have linked your EntityField with your RecordContainer and have no valueProcess specified, then the system takes the value from the record.
  2. Process
    If your EntityField is not linked to the RecordContainer, then the valueProcess is used to determine the value of the variable.
  3. Record process
    This means, you have a mixture of the previous variants: You have linked your EntityField within the RecordContainer and you have a valueProcess specified. If the record returns a value, then it is used, while the valueProcess is being ignored. If, however, the record does not return a value, then the valueProcess is executed to determine a value.

Please mind the following logic:

  • If your system changes into state "NEW" or "EDIT" (e.g., if you open the EditView of a Context), all fields of the Context's Entity are being retrieved (= loaded or calculated) - no matter if they are displayed or only used in other processes. This makes sure that all data are up-to-date when the user edits or enters a dataset.
  • Generally:
    If you open a View (regardless of the system's state), ADITO automatically determines, what fields might be required - meaning not only the fields referenced in the View configuration, but also fields that are used in one of the Entity's processes, like, e.g., the titleProcess or the onActionProcess. These fields are then always loaded (= the column or the expression of the RecordFieldMapping will be included in the SQL's SELECT clause) - even if it later turns out that one or several fields' values are actually not used. This will ensure that all (possibly) required values are immediately present when the client user works with the View - without the system having to load/calculate them separately. On the other hand, this can lead to performance issues, if there are a lot of fields calculated via property expression - especially when these fields' calculation is complex or suboptimally realized. On the contrary, if the field is only calculated via a valueProcess or displayValueProcess (and not via the expression), the calculation is only done on demand. If both types of calculation have been configured, the expression is automatically preferred, if it actually returns a value.

Furthermore, the determination of the $field variable's value depends on the state of the record:

  1. VIEW mode
    In VIEW mode, the user is only Viewing the data and cannot change it. In this mode, the value is determined by the previously stated variants.

  2. EDIT mode
    To determine a value in EDIT mode, the system proceeds as follows:

    • First, it checks if a valueProcess is specified. If so, then it is executed. Thus, the valueProcess can be used to preset a value. (This is where the $this.value variable has to be used (see next chapter).
    • If the valueProcess does not return a value, then the user's input is used.

$this.value

$this.value is a special system variable that is accessible in the valueProcess of an EntityField. It is accessed via vars.get("$this.value") and contains the current value of the EntityField (being input or preset). It can therefore, e.g., be used to determine if something was entered or if the field was completely empty.

important

If the field has no current value, $this.value contains null, otherwise it contains the value entered by the user. If the user has deleted the value, $this.value will return an empty string (no longer null!).

Therefore, if you want to preset a value, you have to check for if( vars.get("$this.value") == null ) to only set your preset value if no value was present before. In the onValidation and onValueChange processes, you can use this to get and process the users input.

Example: Presetting currency to "EUR":

if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && vars.get("$this.value") == null)
{
result.string($KeywordRegistry.currency$eur());
}

Productprice_entity.CURRENCY.valueProcess.js

$this.value vs. $field.MYFIELD

While variable $this.value contains the current value of a field, variable $field.<FIELDNAME> contains the last calculated value that was synchronized to the field. In most cases, those two variables have the same value, due to a close synchronization. There are rare exceptions when the values can differ, e.g.

  • while the initial value of a field is determined;
  • when a record gets reloaded.

$this.value and $field.MYFIELD in valueProcess

Generally, in a valueProcess you have to distinguish between the stored field value ($field.MYFIELD) and the new value to set ($this.value).

Here is an overview about when and how a valueProcess is executed and what reactions are possible:

  1. Initial loading of the field values
    If the value of the field is initially loaded from the Entity, then $this.value is null. This case is mostly used for presets when entering new data oder editing it, because this case occurs only once. If you miss to check for $this.value == null then the value of the field will be overwritten with every refresh.
  2. Field is explicitely set empty
    In case the field is explicitely set empty (e.g., by the user), a check for !this.value would fail, because in this case $this.value == ""
  3. Changes of the field itself
    If the value of the field itself changes directly (e.g., by user input, WriteEntity, neon.setFieldValue, etc.) then $this.value is filled with a value (or an empty string in case 2, see above) and the field itself ($field.MYFIELD) ist empty (""). Knowing this, you can, e.g., prevent that the field is automatically filled by dependencies from other fields, because the given value was entered explicitely.
  4. Trigger of the valueProcess by other fields
    This case only happens when entering new data, not when editing it. It is the constellation that the value of the field itself has not changed, but it has been updated because of triggers/calls etc. and thus the valueProcess is executed. In this case, $this.value and $field.MYFIELD have the same value. This constellation can be used, e.g., to set the field depending on other fields. This is the recommended approach, instead of using neon.setFieldValue in the onValueChange process of another field.
warning

neon.setFieldValue should only be used in onValueChange, if there is absolutely no other possibility to realize the task. The performance of neon.setFieldValue is very low, because many dependencies need to be updated and it can happen that the same code needs to be written in multiple fields.

If the value of a field is set and you do not return anything in the valueProcess, then the set value will be used. (This means, in case 3 only the return must be prevented.)

Example of the implementation of the above cases 1, 3, and 4: The example task is that a field A should initially be filled with value 1, when entering a new dataset. It should be possible to overwrite the field's value when entering a new dataset or when editing it. If field B is set to a specific value, then field A should automatically filled with the value 2 (works for "NEW", not for "EDIT").

var fieldA = vars.get("$field.A");
var thisValue = vars.get("$this.value");

// The value of the field is not required in this case,
// but it can work as trigger, if B changes.
var fieldB = vars.get("$field.B");

var recordState = vars.get("$sys.recordstate");

if([neon.OPERATINGSTATE_NEW, neon.OPERATINGSTATE_EDIT].includes(recordState))
{
if(recordState == neon.OPERATINGSTATE_NEW && thisValue == null)
//case 1: initial presetting the field with value 1
{
result.string(1);
}
else if(fieldA == "" && thisValue)
//case 3: value was changed -> should be set now
{
result.string(thisValue);
// In this case, you can alternatively simply return nothing.
// Then $this.value will be set as field value.
}
else if(fieldA == thisValue)
// case 4: thisValue and field have the same value
// -> The field was not changed, but was triggered somewhere,
// e.g., because a change of field B -> fieldA should be set to 2
{
result.string(2);
}
}

Example valueProcess for cases 1, 2, and 4

$local.value

This is a local system variable that is accessible in the onValidation and the onValueChange processes and contains the entered value before it is written to the variable value, so you can validate it before the data enters the system.

Example: Checking if the user has input a wrong entry date:

var entryDate = vars.get("$local.value");
if (!DateUtils.validateNotInFuture(entryDate)) {
result.string(translate.text("Entrydate must not be in the future"));
}

Activity_entity.ENTRYDATE.onValidation.js

$local.rowdata and $local.initialRowdata

If you want to access the values of EntityFields in specific processes of a RecordContainer, you must exclusively use $local.rowdata or $local.initialRowdata, because $field variables might contain outdated values at that time. In particular, these are the following processes:

note

Find more information on $local.rowdata and $local.initialRowdata in the chapter about $local variables.