# Functions

With functions, you can express advanced conditions or calculations using JavaScript. The JavaScript code is sandboxed and has read-only access to the data sources defined as parameters.

There are two main use cases for functions:

* As a [function property](#function-property) on an **Object Class** or a **Data Source**
* As a [data value](#data-value-function) used in **Action Nodes** and **UI Components**

### Function property

Function properties are runtime-calculated values on an **Object Class** or a **Data Source**. You may reference other properties on the same Object Class or Data Source. For function values on Data Sources, you may also reference properties in other Data Sources, as well as the Data Sources themselves. Data Sources with cardinality `many` become arrays, allowing you to do (read-only) array operations, such as iterations.

This screenshot shows the *All Users* Data Source with a filter including only users missing a value on the *Phone* property.

![](https://29237295-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MiLU-xcHu0eLZiTxcmZ%2F-Mk7U1JqjU_ejnsU5dix%2F-Mk7U9qJXwD3J21RHxaO%2Ffunctions-ds-parameter.png?alt=media\&token=4fd6e889-8c27-4ad7-b639-e182801632c2)

The screenshot below shows the function editor accessed from a function property on an object class.

1. **Self Properties: Properties on the same Object Class or Data Source.** \
   \&#xNAN;*This section is only available when defining functions on data sources or object classes (e.g., a calculated function property, such as the example below).*
2. **App Data: This is all the variables and data sources of your App Data (or Service Data).** \
   \&#xNAN;*You may add whole data sources as function parameters (will give you an array of objects as a function parameter), or you may add a data source property or App Variable as a function parameter (will give you a constant as a function parameter).*
3. **Code Editor: This is where you write code (JavaScript).** \
   \&#xNAN;*You may write as much code as you want, but the code should return some value(s) depending on where you use the function editor. In the below example, we return a string (since the function editor is used for calculating a display property). If the function editor is used to calculate a Visibility Condition, it should return `true` or `false`.*
4. **The added Function Parameters that may be used in the Code Editor.** \
   \&#xNAN;*When adding a data source as a function parameter, it is an array of objects. For example, by adding `projects` as a function parameter, you may perform array operations such as `projects.length`, or you may access properties of the data source (for example, the title of the first entry: `projects[0].title`). The added function parameters are read-only.*&#x20;
5. **Context or Breadcrumb.** \
   \&#xNAN;*It helps you keep track of the context of what you are defining a function for. In the example below, we are defining a function for a data source property. If we were defining a function for a visibility condition on a container, the breadcrum (path) to the UI Component would be displayed.*
6. **Search your App Data.** \
   \&#xNAN;*Makes it easier to locate a property or data source.*
7. **Menus for accessing Enumerated Types or JavaScript libraries to add as Function Parameters.**\
   \&#xNAN;*You may add all enums from the Global Data Model or the built-in enums (such as Language).*\
   *You may add built-in JavaScript libraries such as Math.js.*
8. **Apply Changes.** You may save your function without exiting the editor.

Note that you may use **Find and Replace** inside the code editor and that the editor has **code completion** and **code suggestions**.

<figure><img src="https://29237295-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiLU-xcHu0eLZiTxcmZ%2Fuploads%2FZERUnVnuZoPrBe7uJQjs%2Fimage.png?alt=media&#x26;token=71449d51-e9d8-4ad8-82e7-876f9b7c6e3b" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
When using the Function editor, you may add an App Variable or property of a data source as a Function Parameter. Do *not* try to update the Property directly from the Function editor, Coded Component or Run Code.\
\
When adding an App Variable or the property of a Data Source as a Function parameter, a warning is displayed. The same applies if you e.g. add a Data Source as a Function parameter, and then try to modify a property of that data source through code.\ <img src="https://29237295-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiLU-xcHu0eLZiTxcmZ%2Fuploads%2FqUipJdVxc2oWWa1K5eZY%2Fimage.png?alt=media&#x26;token=d597928a-049b-48f7-82a5-e8dfacde9989" alt="" data-size="original"><br>
{% endhint %}

### Data value

You can use data value functions to return any value type needed. You may include parameters from all available Data Sources, as well as the external libraries.

### Examples

Here are some examples of how to use functions to create custom return values.

A welcome message adjusted to the time of the day, using the **moment.js** library:

```
const hour = moment().hour()

if (hour >= 23 || hour < 5) 
    return `Good evening, ${firstName}`

if (hour < 12)
    return `Good morning, ${firstName}`

if (hour < 17)
    return `Good afternoon, ${firstName}`

if (hour < 23)
    return `Good evening, ${firstName}`
```

Concatenate a person's `firstName` and `lastName` to a full name value:

```
return firstName + ' ' + lastName
```

Check the value of an Enum variable:

```
if (activeEnvironment === production.value) return 'You are in Production'
```

Here, `activeEnvironment` is added from the App Variables, while `production` is added from the built-in enums from the Enum Constants menu (marked as number 7 in the figure above).

## External libraries

The function editor includes a set of external libraries providing advanced functionality.

### Math.js

Math.js is a math library. Visit [mathjs.org](https://mathjs.org/) for more information.

### Moment.js

Moment.js is a library to parse, validate, manipulate, and display dates and times. Visit [momentjs.com](https://momentjs.com/) for more information.

Here are a few examples (remember to add moment.js as a function parameter first):

```
// return last day of month (start of day)
return moment().endOf('month'),startOf('day').toJSON()

// Assuming you have a Datetime property myDate added as a function parameter,
// and you want to set the time-part to a 13:00:00.0
let myNewDate = moment(myDate).hour(13).minute(0).second(0).millisecond(0)
return myNewDate.toJSON()
```

Note that it is necessary to convert the returned `moment.js` object into a Datetime data type. We do that using the `.toJSON()` function.

### Numeral.js

Numeral.js is a library for formatting and manipulating numbers. Visit [numeraljs.com](http://numeraljs.com/) for more information.

### **Other external** JavaScript **libraries**

Inside Apps, you may use other external JavaScript libraries in addition to these (i.e., client-side javascript libraries). You may add them to the Custom Header Tags section of [App Settings](https://docs.appfarm.io/apps/app-settings#custom-header-tags). Once added, you will be able to reference that JavaScript inside the Function editor. However, the autocomplete and code validator will not recognize the reference to the external libraries in the editor, but this warning may be ignored.

<figure><img src="https://29237295-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiLU-xcHu0eLZiTxcmZ%2Fuploads%2FneCapihfL5J6NsdG4KcT%2FFunction%20Editor%20with%20external%20library.png?alt=media&#x26;token=dfc41fe0-a53d-40d2-bc10-f7f3caef7aee" alt=""><figcaption><p>Using an external library in the Function editor</p></figcaption></figure>

## Advanced functions

Functions can be used to handle advanced logic, like data iteration, creation of complex strings, etc.,  using JavaScript.

Below are some examples of common use cases for functions and matching JavaScript code. JavaScript ES6 syntax is used in many of the examples. Semicolons are optional.

### Handle properties that are `null` or `undefined`

By default, all properties in Appfarm (and JavaScript in general) are undefined until a value has been assigned. It may then be blanked (set to null).

The traditional way of handling whether an integer property `myProperty` is `null` or `undefined` is:

```javascript
if (myProperty !== null && myProperty !== undefined) return myProperty
else return 0
```

It can be simplified to:

```javascript
if (myProperty) return myProperty
else return 0
```

Or, a one-liner:

```javascript
return (myProperty ? myProperty : 0)
```

This means: if `myProperty` has a value, return `myProperty`, otherwise return 0.

### Create concatenated strings of properties

You want to create a string containing static text combined with property values. For example, to generate a dynamic welcome message, interpolating the values of the function parameters `firstName` and `companyName`.

```javascript
return `
Welcome, ${firstName}!

You are logged in on behalf of the company ${companyName}.
`
```

This example uses backticks (`` ` ``) at the start and the end. Inside the backticks, you can substitute strings using placeholders (`${propertyName}`). The result is a merged string with line shifts preserved. This concept is known as [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) in JavaScript.

### Check if a filtered data source contains any objects

You have a data source `Companies` containing all companies, and you want to create a condition that evaluates to true if there are any active companies in this data source. A function parameter`companies` is added, with a filter `state EQUALS active:`

```javascript
if (companies.length > 0) return true
else return false
```

Or, as a one-liner:

```javascript
return companies.length > 0
```

### Return a single value from an array

You have a data source `Companies` with cardinality `many`. Companies are added as a function parameter, with a filter applied, resulting in this array containing 1 or 0 objects. You want to return the property `Company Name`  if the filter resulted in an object, and `null` otherwise:

```javascript
if (companies.length > 0) return companies[0].companyName
else return null
```

Or, as a one-liner:

```javascript
return companies.length > 0 ? companies[0].companyName : null
```

{% hint style="info" %}
**Good to know**

When adding whole data sources as function parameters, they are treated as arrays inside the function editor, as in the above example. However, you cannot to refer properties more than one level deep. In other words, if you add `Contacts` as a function parameter, you cannot access `contacts[0].company.name`.

In this case, you need to add a runtime property (function) to the `Contacts` data source (for example `companyName`, returning `Contacts.Company.Name`) and refer to this property as `Contacts[0].companyName`.
{% endhint %}

### Return a reference to an object

You have a data source `Order Lines` and need a property `Company` on this data source. However, `Company` is located at `Order Lines.Order.Company`.

The solution is to create a runtime property on the `Order Lines` data source, with data type **Company**, and property type **Function**. Add `Order Lines.Order.Company.ID` as a function parameter:

```javascript
return id
```

Note that if you add an array as a function parameter, and want to access the built-in ID property of an object, you need to use **Node Name,** which is `_id`.

### Aggregate / accumulate data from an array

You have added `salesLines` as a function parameter, an array containing all relevant sales to be accumulated. You want to sum the `Amount` property of the sales. When referring to properties of an array added as a function parameter, you need to use the **Node Name** (as defined in the [object class properties](https://docs.appfarm.io/data-model/object-classes#object-class-properties)) of this property. In our case, the **Node Name** of `Amount` is `amount:`

```javascript
return salesLines.reduce((agg,obj) => (agg + obj.amount), 0)
```

If `amount` could potentially be undefined or null, we could handle that as follows:

```javascript
return salesLines.reduce((agg,obj) => (agg + (obj.amount ? obj.amount : 0)), 0)
```

### Filter an array inside the function

You have added `salesLines` as a function parameter, an array containing all sales. You want to filter only those with a positive `amount`, and save this array to a new array `salesLinedFiltered`.

{% code overflow="wrap" %}

```javascript
// Loop all instances, and keep only those matching the condition amount >= 0
let salesLinesFiltered = salesLines.filter(obj => obj.amount >= 0)
```

{% endcode %}

Note that in this example, you would typically just apply a filter to the function parameter `salesLines` (with the expression `amount >= 0`). This code sample is just to demonstrate the filter method of JavaScript arrays.

### Convert an array of objects into an array of simple data types

You have a `Companies` data source, with a property `Company Name` (**Node Name**: `companyName`). You want to return a comma-separated list of all company names. For this, we need to convert the array of objects to an array of strings, and then join the strings with a comma.

{% code overflow="wrap" %}

```javascript
// Map all Company objects into an array of strings, and then join the strings
let companyStrings = companies.map(obj => obj.companyName)
return companyStrings.join(',')
```

{% endcode %}

### Convert an array of objects into an array of alternative objects

You have a `Companies` data source, with the properties `companyName` and `organizationNumber`. You would like to convert this to a list of objects with the properties `name` and `orgNo`. This might be used in a [service](https://docs.appfarm.io/reference/services) (as the custom response body of an [endpoint](https://docs.appfarm.io/reference/services/service-endpoints)) when you want to return a list of objects with property names according to some specific cases, or with only a small set of properties from the `Companies` data source.

{% code overflow="wrap" %}

```javascript
/*
'companies' is added as a function parameter.
An array is returned since this is common when returning a custom response body from a service endpoint.
*/ 
let newCompanyList = companies.map(comp => ({name: comp.companyName, orgNo: comp.organizationNumber}))
return newCompanyList

// If you need to return a string: return JSON.stringify(newCompanyList)
```

{% endcode %}

### Create a nested JSON structure from two data sources

You have an [endpoint](https://docs.appfarm.io/reference/services/service-endpoints) that returns data to an external system. There are two data sources, `Orders` and `Order Lines`, and you would like to return a list of orders and, for each order, a list of related order lines.&#x20;

```javascript
/*
'orders' and 'orderLines' have been added as function parameters.
'orderLines' holds the order lines for all of the orders.
*/
return orders.map(order => ({
    _id: order._id,
    title: order.title,
    customer: order.customerName,
    lines: (orderLines.filter(line => line.orderID === order._id).map(line => ({
        _id: line._id,
        product: line.productName,
        qty: line.quantity,
        price: line.price
    })))
}))
```

### Sort an array of objects

You have a data source `Orders` and want to return the `Order Date` (**Node Name**: `orderDate`) of the first order.

```javascript
let ordersSorted = orders.sort((a,b) => (a.orderDate > b.orderDate) ? 1 : -1)
return ordersSorted[0].orderDate
```

Note that in this example you could just use the Sort objects action node on the `Orders` data source (sorted `Ascending` by `Order Date`) prior to adding it as a function parameter, and having a function return `orders[0].orderDate`.
