Event Flow

Event Flow #

Varv is a reactive and event-based system. Events in Varv are data objects that are used to transfer information. They are emitted from triggers, passed on to actions, and then terminate once an action is performed.

Events in Varv contain contexts and shared variables. An event can have any number of contexts including none. A context, again, consists of a target and context variables. The following figure illustrates this:

Event Contexts #

A context is, like an event, a data object. An event can have multiple contexts, because actions might need to work on multiple instances at once and do something for each of them. This is inspired by JavaScript’s array methods such as map.

Targets #

The target of a context is a reference to a concept instance, e.g., target: "concept1884608cc3ab6e04cd9b". Each context has to have a target. The target is used by many actions to define on which instance an action should work on. For instance, consider a todo concept that has the string property "text". The action { "length": "text" } computes the length of the "text" property. In order to know from which instance the action should take the property from, the target is used.

Selection and Changing of Targets #

The set of all targets in all contexts is what we call the selection of an event. When an event is created, the selection can be set by the trigger, for example, when clicking on an element in the DOM View that represents a concept instance, the "click" trigger selects this concept and sets it as the target.

In action chains, the selection is mainly modified by using the "select" action. This action makes it possible to select all or a subset of all instances of a concept type. Consider the following example:

In the first column, the selection is set to the todoList by the "click" trigger when the user clicks on the todo list. Next, the "select" action changes the selection to all instances of todo. As there are three, the event now has three contexts. The previous selection is omitted when selecting a new set of instances.

Context Variables #

Once an action, like "length" in the third column of the above example, is executed, the result of the computation will be stored as a variable in the context variables. If, for example, three todo instances are selected, the value will be stored within each context’s variables.

Lastly, the "where" action is used in the fourth column to filter the current selection and remove all whose length is greater or equal to 4.

Filtering in "select": The filtering functionality of the "where" action can also be used directly in the "select" action (and other actions). Refer to the Actions section of the user guide for more information.

Bulk or For-Each Mode #

When working with events with multiple contexts, it might be that an action works on all of them at once in bulk or it works for each of them. For example, the "select" might want to replace the old selection completely or might want to perform a selection for each element currently in the selection. By default, the bulk mode is used, which does one selection and replaces the current selection.

An example, could be the following action, which increments a counter each second for each todo instance:

{
    "concepts": {
        "todo": {
            // ...
         },
         "counter": {
            "schema": { "count": "number" },
            "actions": {
                "incrementByNoTodos": {
                    "when": { "interval": 1000 }, // Every second
                    "then": [
                        { "select": "todo" },     // Select all todos
                        { "select": {             // Select the counter once for each todo
                            "concept": "counter",
                            "forEach": true
                        }},
                        { "increment": "count" } // Increment the counter once per counter
                                                 // in the selection, i.e. todo.
                    ]
                }
            }
         }
    }
}

Empty Events and Shared Variables #

Most of the time an event has at least one target in its selection. In some cases, however, it might be useful to pass an event without a target to the next action. In such cases, an empty event without any contexts is passed on to the next action. This is, however, limited as many actions require a target to work on. For some actions, e.g., "select", it is possible to be executed without a current selection.

Variables are normally stored in contexts, so when all contexts of an event are removed, e.g., using "where", then also all variables are lost. Some variables, however, might still be useful later in the action chain, for instance, in the above example the information about mouseX and mouseY. Therefore, Varv stores all variables, which have the same value in all contexts, as shared variables inside the event. Once new contexts are added to the event, all shared variables are added into all contexts again.

Empty Event Example #

Consider the following example, whenever we remove a todo item, we want to store its text in a property in another concept:

{
    "concepts": {
        "trash": {
            "schema": { "lastDeletedText": "string" }
        },
        "todo": {
            "schema": { "text": "string" },
            "actions": {
                "deleteOnClick": {
                    "when": { "click": "todo" },
                    "then": [
                        { "get": {
                            "property": "text",
                            "as": "lastText"
                        }},
                        "remove",
                        { "select": "trash" }
                        { "set": { "lastDeletedText": "$lastText" }}
                    ]
                }
            }
        }
    }
}

The "remove" action deletes the todo instance and the context is removed from the event. However, an empty event is passed on so that the "select" action, which selects the trash concept instance. The "set" action can still set the "lastDeletedText" property using the lastText variable in the shared variables of the event.

stopIfEmpty Parameter #

When the "select" or "where" action should not pass an empty event forward, the parameter stopIfEmpty can be used, which defines that if the event is empty after the selection/filtering, it should not pass an event forward.

In the following example, the action chain is stopped at the "where" action if there are no todo instances that have an empty name.

{
    "removeEmptyTodosAction": [
        { "select": "todo" },
        { "where": {
            "property": "text",
            "equals": "",
            "stopIfEmpty": true
        }},
        "remove"
    ]
}

Event Flow Modifications #

Events are usually passed on from one action to the next in the chain. Sometimes, however, one might want to run an action without modifying the event or to run different actions depending on a condition. Varv offers a variety of actions that allow to modify the event flow: the "run", "switch", and "exit" actions:

Flow Action Description
"run" This action takes another action name as a parameter, runs that action’s action chain, and then returns to the parent chain and continues with the same event as before the "run" action.
"switch" This action acts as a switch-case construct that allows to continue with different actions chains depending on a certain condition. For more detail refer to the action’s documentation.
"exit" This action simply stops the action chain and does not pass on an empty event.
Flow Actions: The flow actions are also documented in more detail in the Flow Actions section of the user guide.

© 2023 Aarhus University | Made by cavi.au.dk | Contact Person: Clemens Nylandsted Klokmose