Expressions



Intro

Besides static field properties such as visible and required, you can also define dynamic field properties. These are called expressions and the JSON keys are suffixed with Expression, for example, "visibleExpression" and "requiredExpression".

The values of expression field properties are evaluated at runtime against actual values in the app, which is what makes them dynamic. For example, you can define “The Remarks field is visible only if the Subject field is greater than 20 characters” and the runtime app behavior is that as soon as the user types in more than 20 characters in the Subject field the Remarks field appears automatically.


Expression Types

The following JSON fields supporting expressions exist:

Expression Type Validation
“visibleExpression” Must evaluate to a boolean value.
“editableExpression” Must evaluate to a boolean value.
“requiredExpression” Must evaluate to a boolean value.
“defaultValueExpression” Must evaluate to a string, number, boolean, datetime or duration (in milliseconds) value.
“validationExpression” Must return a boolean value indicating if the entered value is valid or not.

Note:

  • There is no static “validation” property, just "validationExpression".
  • An additional property called "validationErrorMessage" is supported, containing a message to be displayed when the validation defined by the "validationExpression" fails.
  • "validationErrorMessage" - it defines the text to be displayed to the user when the field is not valid according to the above condition. If this is translated, then it will contain the text from the translations file.

Expression Priority

If an expression is present, then the corresponding static property is ignored. For example, if "visibleExpression" is present, "visible" is ignored. However, if the expression evaluation yields an error which means the expression is incorrect, then the code falls back to the corresponding static property and use it instead. For example, if "visibleExpression" can’t be evaluated for some reason, "visible" is used if present.

If both the static property and the expression (for example, "visible" and "visibleExpression") are missing, the application logic is used. So, if it’s intended that the default application logic is used for a field, then in the (default) screen configuration for that field, there should be nothing set for ‘visible’, ‘editable’, ‘required’, and so on, and their “Expression” counterparts.

Exception to this is the "validationExpression". The validation defined by it runs in addition to the default validation which already exists in the apps. The reason is that the default validation which already exists probably has a very good reason for existing, so by defining a "validationExpression" you shouldn’t override the existing validation logic, but rather enrich it.


Expression Format

All “xyzExpression” types are written in the same way: they’re some chunk of Javascript code which gets evaluated at runtime. This code can be:

Application Independent

  • "new Date() > new Date(2000, 1)" means that today’s date is later than January 2000.
  • This expression code uses no data from the application itself.
  • Any and all built-in javascript functions and data types may be used.

Screen Dependent

  • "${serviceCall.subject} === 'SuperCall'" means that the Subject of the Service Call must match exactly the text 'SuperCall'.
  • In this case, "${serviceCall.subject}" is a variable which the application will substitute at runtime with its actual value.
  • This value can also be not set which means the user hasn’t entered anything in the subject field.
  • The variable may only reference data already loaded in the UI of the screen being customized. For example, for the ServiceCall details screen, since it loads and shows the BusinessPartner, the variable "${serviceCall.businessPartner.name}" is valid, but "${serviceCall.businessPartner.defaultContact.name}" is not.

Application Dependent

  • Variables that don’t reference something from the screen, but reference some global objects from mobile applications.
  • Similar to the screen dependent variables, they are also replaced at runtime.
  • The list of the global variables that are currently supported by the mobile applications are:
    • currentProfile: it refers to the ProfileObject DTO (only one for each company). It only supports the 'userAccountGroupName' property from the DTO definition, for example, "${currentProfile.userAccountGroupName} === 'ALL'".
    • currentUser: it refers to the Person DTO that refers to the user who’s currently logged in. It supports all 27 properties of the Person DTO definition, for example, "${currentUser.firstName} === 'Joe':
      • ${currentUser.userName}
      • ${currentUser.remarks}
      • ${currentUser.branchName}
      • ${currentUser.manager}
      • ${currentUser.refId}
      • ${currentUser.firstName}
      • ${currentUser.externalResource}
      • ${currentUser.emailAddress}
      • ${currentUser.departmentName}
      • ${currentUser.homePhone}
      • ${currentUser.skills}
      • ${currentUser.positionName}
      • ${currentUser.branchCode}
      • ${currentUser.lastName}
      • ${currentUser.plannableResource}
      • ${currentUser.mobilePhone}
      • ${currentUser.id}
      • ${currentUser.fax}
      • ${currentUser.skypeName}
      • ${currentUser.positionCode}
      • ${currentUser.code}
      • $currentUser.officePhone}
      • ${currentUser.type}
      • ${currentUser.jobTitle}
      • ${currentUser.pager}
      • ${currentUser.departmentCode}
      • ${currentUser.otherPhone}

Customer Specific

  • "satisfiesCustomRule(${serviceCall.subject})": in this case, "satisfiesCustomRule" is a customer-defined function which can be added in the cloud by yourself.
  • At runtime, the application substitutes the value of the "${serviceCall.subject}" variable and the function is called.
  • The code of the function is completely your responsibility, and the application doesn’t validate it in any way.
  • Only simple functions are supported which means no promises, http calls, and so on.
  • The cloud DTO used for this is “Function DTO” and they can be managed in the admin portal.

A Mix of Dependencies

"isValidSubject(${serviceCall.subject}) && new Date() > new Date(2000, 1) && ${serviceCall.remarks}.length > 20"


Variable Substitution

Since the expressions can contain variables, the actual values for the variables must be substituted by the apps at runtime before evaluating the expressions.

The following (conceptual) variable data types are supported:

  • string
  • number
  • datetime
  • boolean
  • duration

Since each application represents these data types differently (technology-specific), each application is responsible for converting from its representation to a valid Javascript representation of the value before evaluating an expression. However, independent of application/technology there are some common guidelines for this conversion so as to ensure that the Javascript expression evaluation works the same independent of platform. Here’s how each data type must be converted to its equivalent Javascript value:

  • If it has a value (how this is represented on each platform doesn’t matter):
Data Type Conceptual value Javascript Value Example(s) Remarks
string something ‘something’ Expression: "${person.name}.length > 20"
Value: Adrian
After substitution: "'Adrian'.length > 20"
In the expression, there are no quotes. The app will take the actual value and wrap it in quotes.
number 3.14 3.14 Expression: "${mileage.distance} > 20"
Value: 55.3
After substitution: "55.3 > 20"
This example uses US/UK time notation standard. If the app is displayed in German, the value “3,14”, after conversion in Javascript, will be “3.14”.
datetime value new Date (value_as_unixtimestampmilliseconds) Expression: "${serviceCall.startDate} > new Date()"
Value: whatever serviceCall.startDate is
After substitution: "new Date(xxx) > new Date()" where xxx is the value of serviceCall.startDate converted to a unix timestamp in milliseconds.
There are several potential options for converting datetime:
- simply unix timestamp
- string
- javascript Date
The latter gives the most flexibility, as there are also methods available to call on it. For example, if you want to check that the date is in December, you can do "${serviceCall.startDate}.getMonth() == 11", which at runtime will be converted into "new Date(value).getMonth() == 11".
duration value value in milliseconds Expression: "${effort.duration} > 1000"
Value: value_in_milliseconds
After substitution: "value_in_milliseconds > 1000"
This example uses US/UK time notation standard.
The expression of duration doesn’t work in IOS or Android.
boolean value true | false Expression: "${activity.isPersonal}"
Value: true
After substitution: true
In the CSServiceCallDetail and CSActivitySidebar screen configurations, the expression should be in the ${activity.udfMeta.isbool} === 'true' format. The expression of boolean doesn’t work in IOS or Android.
array array with objects: “string1”, “string2” [‘string1’, ‘string2’] Expression 1: "${someArrayOfStrings}.length > 0"
Value: ['string1', 'string2']
After substitution: "['string1', 'string2'].length > 0"
Expression 2: "${relation.checklists}.length > 0"
Value: [checklist1DTO, checklist2DTO]
After substitution: "['checklist1ID', 'checklist1ID'].length > 0"
There are two types of array supported:
- arrays of basic types, see Expression 1.
- arrays of DTO types, in this case the elements of the array will be the cloud IDs of those DTOs - see Expression 2.
  • If it doesn’t have a value which means the user hasn’t entered any data yet:
    • For all data types, the Javascript representation should simply be undefined.
    • For example, if you want to have the Remarks field visible only if ServiceCall.Subject has a value, the visibleExpression would be "${serviceCall.subject} !== undefined" and if the Subject has a value “abc”, it would at runtime become "'abc' !== undefined" which evaluates to true.
    • When validating a value, you must always consider the case that the value might be empty. For example, check if the field value has a certain length: ` “validationExpression”: “${mileage.source} != undefined && ${mileage.source}.length > 3” `