Skip to content

Pointers and Contexts

BizzStream expressions use pointers to reference specific field values or line-level values within documents, similar to cell references in spreadsheets. In this article, we'll explore the concept of pointers and how they work in BizzStream expressions.

Let's explore how pointers work using the following timesheets document:

{
    "name": "Joe Smith",
    "approvalDate": "2023-05-01",
    "totalHours": 15,
    "equipmentId": "67ae05cfd2938baf6ebf4941",
    "timesheets": [
        {
            "_id": "a9ac590a-cb64-4186-9c92-a0317bb7a36b",
            "date": "2022-04-22",
            "hours": 5
        },
        {
            "_id": "f8bc3cff-a492-4e9e-8d6c-e51497fd0461",
            "date": "2022-04-23",
            "hours": 10
        }
    ],
    "remarks": [
        {
            "_id": "57145777-bc4a-45a9-a818-49d525e9d720",
            "authorId": "73a3e8b1-9e74-4b9c-a271-f960b0e932e4",
            "remark": "Just a normal day"
        }
    ]
}

Pointers

Pointer Type Syntax Example Description
Field Pointer F["name"] Accesses a specific field in a document.
Reference Field Pointer REF["equipmentId"].F["name"] Accesses a field in a referenced document.
All Lines Pointer L["timesheets"][*] Retrieves all lines from a Line Block.
Single Line Pointer L["timesheets"][0] Retrieves a specific line (zero-based index).
Line Field Pointer L["timesheets"][*].F["hours"] Retrieves a specific field from all lines.
Source Line Field Pointer SRL.F["hours"] Retrieves a field from the current line.
Control Pointer CTRL["timesheetsGrid"] Refers to a control in a layout.
Layout Pointer LAY["name"] Accesses a layout.
Dataset Pointer DS["datasetInOverlayLayout"] Accesses a dataset in an overlay target layout.
Overlay Layout Target Pointer OVRLTGT.DS["datasetInOverlayLayout"] Accesses a dataset in an overlay target layout.
Overlay Layout Source Pointer OVRLSRC.DS["datasetInSourceLayout"] Accesses a dataset in an overlay target layout.

Field Pointer

When you want to get the value of the field "name" in a document, you should use the pointer:

F["name"]

Given the timeheet example document, this expression resolves to "Joe Smith".

In order to get the value of a reference field, the pointer to use is different, because you need to reference a value in the reference document:

REF["equipmentId"].F["name"]

The first part REF["equipmentId"] points to the reference field. The second part, .F["name"]points to the "name" field in the reference document.

All Lines Pointer

To refer to all the "timesheets" lines in a document, you should use the following pointer:

L["timesheets"][*]

This returns an array of all lines including all fields, in this case

[
    {
        "_id": "a9ac590a-cb64-4186-9c92-a0317bb7a36b",
        "date": "2022-04-22",
        "hours": 5
    },
    {
        "_id": "f8bc3cff-a492-4e9e-8d6c-e51497fd0461",
        "date": "2022-04-23",
        "hours": 10
    }
]

Single Line Pointer

When you want to refer to a specific "timesheets" line in a document, you should use the pointer:

L["timesheets"][0]

Here, the number enclosed by the square brackets is the index of the line in the array. This index is zero-based, which means that the first element has index 0. When such an expression is resolved, it will return the content of the line, in this case:

{
  "_id": "a9ac590a-cb64-4186-9c92-a0317bb7a36b",
  "date": "2022-04-22",
  "hours": 5
}

Line Field Pointer

When you want to refer to a field in all lines, you can use the following pointer:

L["timesheets"][*].F["hours"]

This will return an array of the hour values, in this case [ 5, 10 ].

Source Line Field Pointer

If you are in a document line in a Document Dataset, and want to refer to a field within the same line, you can use this pointer:

SRL.F["hours"]

Thus, when the following expression is resolved for the first "timesheets" line in the example document, it yields 5. When it is resolved for the second line, it yields 10.

Field Pointer in Filter Datasets

In filter datasets, pointers will resolve to an array, instead of a single value. This way it accomodates for the fact that a Between Filter uses two values. In order to access data from a Filter Dataset field you may use the BizzStream expressions similar to field pointers. Let's try and access a "startDate" filter field:

F["startDate"]

The result is an array where index 0 holds the first filter value (filterValue1), and index 1 holds the second value (filterValue2), if applicable. If the filter operator is between, filterValue2 will be populated; otherwise, it remains undefined.

So F["startDate"] resolves in the context of a filter dataset to ["2024-07-05", "2024-07-08"].

To access only "filterValue1" you may use this pointer in combination with the INDEX operator.

INDEX(F["startDate"], 0)

This will result in the string "2024-07-05".

Control Pointer

When you want to point to control in a layout, you can use the control pointer. For example, the pointer CTRL["timesheetsGrid"] refers to a control with the name "timesheetsGrid". Control pointers can only be used in combination with the SELECTED and CHECKED control operators.

The special control pointer CTRL["treeview"] will point to the treeview control. With the SELECTED you use it to find which item is selected. SELECTED(CTRL["treeview"], "name") will get the name of the selected item.

Layout Pointer

To point to a layout, you may use a Layout pointer. This pointer can be used to point to fields in different layouts. For example LAY["name"].DS["test"].F["name"] points to field "name" in the dataset "test" in the layout "name".

Layout pointers can also be used in combination with the ISOVERLAYLAYOUT operator to verify that a layout is used for the purpose of an overlay layout.

ISOVERLAYLAYOUT(LAY["ordersOverview"])

Dataset Pointer

You can point to a dataset by using a dataset pointer like DS["test"]. In a single item dataset it will resolve to the document. This means that you can access fields directly with DS["test"].F["fieldName"]. In a list dataset, the dataset will resolve to all documents. You have to use an index to access a single document, or use the asterisk to access all documents: DS["test"][*].F["fieldName""].

In overlay layouts, pointers can be used to define whether a dataset can be found in the overlay layout or in the source layout.

OVRLTGT.DS["datasetInOverlayLayout"]
OVRLSRC.DS["datasetInSourceLayout"]

Indexing Menu Pointers

You can access specific data within a dataset from a previous menu using its index. This is useful when you need to pinpoint a value from a particular dataset within a chained menu flow.

Example:

{{M[-1].DS["dataset2"].F["price"]}}

Explanation:

  • M[-1] refers to the immediate previous menu in the chain.
  • DS["dataset2"] targets the dataset named "dataset2" within that menu.
  • F["price"] then retrieves the field value of the "price" field from the dataset "dataset2".

Checking if a Menu Exists

It's often helpful to check if a specific menu exists before attempting to access its properties. This can prevent errors in your expressions.

Example:

{{IF(EXISTS(M[nameOrIndex]),ifExp,elseExp)}}

Explanation:

  • EXISTS(M[nameOrIndex]) checks if a menu, identified by its nameOrIndex (either its name as a string or its numerical index), is present in the menu chain. For more information about the EXISTS operator see this documentation.
  • ifExp is the expression that will be evaluated if the menu exists.
  • elseExp is the expression that will be evaluated if the menu does not exist.

O (Object) Operator

The O operator is used to reference and manipulate fields within a document.

Syntax

O[pointer]

Parameters:

  • pointer: A reference to the desired field within the document.

Examples

  • O["coordinates"].F["formattedAddress"]: This retrieves the formattedAddress field from the coordinates object, typically representing a geolocation field.

Pointers that Cannot be Resolved

In some cases, BizzStream cannot resolve a pointer, for instance because a field does not exist. In that case, the expression will yield the undefined value.

Contexts

When a BizzStream expression is calculated, its context is taken into account. The context of a BizzStream expression determines which document(s) or layouts it applies to, based on where the expression is used.

Document Definition

BizzStream expressions that are used in a document definition are resolved in the context of the document. For instance, the BizzStream expression used to determine whether the Terminate rule should be triggered, uses the document that the action processes as context.

Layouts

When BizzStream calculates expressions in layouts, it needs to know exactly which dataset to use. If you need to reference to a dataset outside the scope of the current layout, you have to provide additional context. The context that BizzStream needs, consists thus of two elements:

  1. The name of the menu block that renders a layout.
  2. The name of the dataset within the menu block.

This information can be provided by prefixing the pointers. For instance, the BizzStream expression M["timesheetDetails"].DS["timesheet"].F["name"] resolves to the "name" field (F["name"]) in the "timesheet" dataset (DS["timesheet"]) in the "timesheetDetails" menu block (M["timesheetDetails"]).

Multiple contexts can be used within a single BizzStream expression. For example, the expression M["clientDetails"].DS["clientInfo"].F["totalRevenue"] + M["orderDetails"].DS["orderInfo"].F["totalRevenue"] adds the value of the "totalRevenue" field within the "clientInfo" dataset in the "clientDetails" menu block to the "totalRevenue" field within the "orderInfo" dataset in the "orderDetails" menu block.

Controls Linked to a Dataset

In many cases, expressions that are used in controls linked to a dataset should be resolved in the context of that same dataset. In that case, it is not necessary to extend the pointer with information about the dataset and menu block.

For example, suppose we have a layout with a Document Dataset containing a timesheet. We can configure an expression to disable a control in the layout if the field approvalDate has a certain value. If that control is linked to the same dataset as the approvalDate field, the dataset pointer is not required. These two expressions are equivalent:

F["approvalDate"] > "2022-05-10"
M["timesheetDetails"].DS["timesheet"].F["approvalDate"] > "2022-05-10"

The first version is preferred for readability.

Same layout, Different Dataset

Likewise, if you want to resolve a BizzStream expression in the context of another dataset in the same layout, it suffices to extend the pointer with a dataset context. For example, DS["approverInformation"].F["name"] is the same as M["timesheetDetails"].DS["approverInformation"].F["name"].

Control Pointers and Context

Because control names should be unique within a layout, control pointers can only be extended with menu block information:

M["timesheetDetails"].CTRL["timesheetsGrid"]

Again, it is not necessary to provide menu block information if the control resides in the same menu block.

Pointers in BizzStream expressions used to determine whether path from one menu block to another should be followed, the path conditions, are always resolved in the context of the menu block layout. This implies that it suffices to extend the pointer with a dataset prefix.

However, if you want to use a dataset in another menu block, you should extend the pointer with a menu block prefix.

For more information on how menus work, see the menu documentation.