# Expressions

Expressions enable you to access property values and other data for dynamic output.
Use expressions to reference the data from your data providers and view the definition schema throughout a view. You can also use expressions to calculate, format, or transform data fields.

:::tip
You don't need to implement a view data provider to use expressions that reference `views.properties` because Apex SDK for Slack does that for you.
:::

There are two types of expressions.

- Data provider expressions
- Formula expressions

Expressions must be enclosed in brackets like `{!expression}`.

The `{!}` wrapper tells the framework that the string is an expression that must be resolved.

## Data Provider Expression Syntax

To write an expression, use the `key` of the data provider reference. The framework resolves the expression to the value from the corresponding data provider and renders the value in the view.

Data provider expressions follow this period-delimited string syntax.

```yml
"{!<key>.<tokens>}"
```

- `<key>` maps the expression to a data provider.
- `<tokens>` are references to properties from the data provider.

For example, `{!view.properties.*}` represents an expression that resolves data passed into the view. See [View Expression Syntax](#view-expression-syntax).

To determine the valid properties, check the documentation for the data provider you're using. For example, `{!record.data.fields.Name.value}` is from the record data provider backed by [UI API](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_responses_record.htm).

For a data provider that returns a primitive, the expression looks like `{!key}`.

For a data provider that returns an object, the expression uses properties specific to the object definition, such as `{!contact.Name}`.

You can also reference an expression of any type within a string, which makes it easy to construct variable strings.

```yaml
"There are {!view.properties.numResults} results found!"
```

For more information, see [Implement a Data Provider](/docs/platform/salesforce-slack-sdk/guide/data-providers.md).

:::important
All expressions in view definitions are case-sensitive. For example, `{!label.labelName}` works but `{!Label.labelName}` doesn't.
:::

### View Expression Syntax

View expressions are special data provider expressions that are resolved from data passed into the [view](/docs/platform/salesforce-slack-sdk/guide/views.md).

View expressions follow this period-delimited string syntax.

```yml
"{!view.<category>.<tokens>}"
```

- `<category>` maps to the type of top-level data passed into the view. Currently, only `properties` is supported.
- `<tokens>` are the references to the top-level view data. For example, `{!view.properties.objectApiName}`.

Here's an example view that contains several expressions.

```yaml
schema:
  properties:
    bodyText:
      type: string
      required: true
    headerText:
      type: string
      defaultValue: "Welcome Home"
components:
  - definition: home
    components:
      - definition: header
        properties:
          text: "{!view.properties.headerText}"
      - definition: section
        properties:
          text:
            type: "mrkdwn"
            text: "{!view.properties.bodyText}"
      - definition: divider
```

### Custom Label Expression Syntax

Custom label expressions resolve to custom labels in Salesforce.

```yaml
"{!label.<namespace>.<labelName>}"
```

- `<namespace>` is the optional namespace. `c` is the default namespace. Include the namespace if your org has a namespace or to access a label in a managed package.
- `<labelName>` is the name of the label. See [Work with Custom Labels](/docs/platform/salesforce-slack-sdk/guide/localization.md#work-with-custom-labels).

## Formula Expression Syntax

Formula expressions help you calculate values dynamically, such as to enforce a validation rule or apply a value on a field when a user creates a record. It’s based on
the Salesforce Formula Engine library \[[GitHub Repo](https://github.com/salesforce/formula-engine)].

For details of the formula syntax,
operators, and functions, see [Formula Operators and Functions](https://help.salesforce.com/s/articleView?id=platform.customize_functions.htm\&type=5) in Salesforce Help.

Formula expressions follow this general format:

```yaml
{ !formula_expression  }
```

:::important
Apex SDK for Slack currently has limited support for formula expressions. Expressions that include string concatenation by using the `+` operator and functions such as `SUBSTITUTE()` and `LABEL()` aren’t yet supported.
:::

Here are a few formula expression examples.

- This example uses a data provider expression to resolve to a name value on a record field. For example, `John Smith`. In general, any valid data provider expression can be referenced by a formula field.

  ```yaml
  "{!record.data.fields.Name.value}"
  ```

- This formula expression calls the [`FORMAT` function](https://help.salesforce.com/s/articleView?id=platform.customize_functions_parent.htm\&type=5).

  ```yaml
  { !FORMAT(label.help.headerTemplate , commandInfo.commandName) }
  ```

  `label.help.headerTemplate` is a label provider expression that resolves to a text template pattern. `commandInfo.commandName` is an iteration data provider expression, where `commandInfo` is the iteration item. If `label.help.headerTemplate` resolves to `"*Command*: {0}"` and `commandInfo.commandName` resolves to `"search"`, then this expression evaluates to a String value of `"*Command*: search"`.

:::note
We recommend using the `FORMAT` formula function to handle your string templating use cases.
:::

## Bind Data to a View

You can bind your expressions to a view by referencing its schema. Here's a simple view with a default string passed into its `view.properties` schema.

```yaml
description: An test page
schema:
  properties:
    title:
      type: string
      defaultValue: "World"
dataproviders:
  label:
    definition: label
    properties:
      lang: en
components:
  - definition: section
    properties:
      text: "Test Page"
  - definition: section
    properties:
      text: "Message: {!FORMAT('Hello {0}! This is a {1}', view.properties.title, 'test.')}"
```

Let's look at the expression in the view.

```yaml
{!FORMAT('Hello {0}! This is a {1}', view.properties.title, 'test.')}
```

The expression resolves to `Hello World! This is a test.`

`{0}` and `{1}` are placeholder tokens that resolve to the second argument and third argument to the FORMAT function respectively. So, `{0}` resolves to `World`, provided by `view.properties.title`.

You can also bind a view to a data provider by using the `record` key.
This example uses the `record_detail_message.view` view from the [sample app](/docs/platform/salesforce-slack-sdk/guide/setup-install-app.md).

The view has one data provider with the `record` key. The data provider determines the structure of the returned data. This data provider is backed by [UI API](https://developer.salesforce.com/docs/atlas.en-us.uiapi.meta/uiapi/ui_api_responses_record.htm).

```yaml
"{!record.value}"
```

The view has one input property, `recordId`. To use the value of `recordId` in the view, build an expression by using `view.properties`.

```yaml
"{!view.properties.recordId}"
```

The view definition looks like this.

```yaml
description: "This component displays record details in a message"
schema:
  properties:
    headerText:
      type: string
      defaultValue: "Record Details"
    recordId:
      type: string
      required: true
    objectApiName:
      type: string
      required: true
dataproviders:
  record:
    definition: "apex__RecordDataProvider.getRecord"
    properties:
      recordId: "{!view.properties.recordId}"
      objectApiName: "{!view.properties.objectApiName}"
components:
  - definition: message
    components:
      - definition: header
        properties:
          text: "{!view.properties.headerText}"
      - definition: divider
      - definition: iteration
        properties:
          foreach: "{!record}"
          foritem: "record"
        components:
          - definition: section
            properties:
              text:
                text: "{!record.label}: {!record.value}"
                type: mrkdwn
```
