You use ViewModel variables to refer to the current user focus, selected rows, the running ViewModel, and values you define yourself when building a ViewModel for a UI, API, report, or server-side job.
What ViewModel variables are
A ViewModel variable is a named, typed value available while the ViewModel runs. MDriven maintains some variables automatically, and you can declare variables for state that your ViewModel needs.
For example, a grid nesting named Order can provide vCurrent_Order for the row the user last focused. An in-view action can use that value to act on the focused order.
The available variables depend on how the ViewModel is used. A cursored UI ViewModel has focus and selection variables; a report or API ViewModel may not use those variables in the same way. Always inspect the variables offered by the editor in the expression or action where you are working.
Built-in variables
Built-in ViewModel variables are supplied by the framework or client when the relevant variable exists in the ViewModel.
| Variable | Meaning | Example use |
|---|---|---|
vCurrent_<NestingName>
|
The object currently focused or last clicked by the user in the named ViewModel nesting. | vCurrent_Order identifies the Order row currently focused in an Order grid.
|
vSelected_<NestingName>
|
A collection of selected objects for the named nesting when the grid allows multi-select. | An action can process every Order in vSelected_Order.
|
self
|
The object currently being rendered in the expression's ViewModel class. | In an attribute expression in a detail ViewModel class, self is that detail object.
|
selfVM
|
The running ViewModel. | Use it in action-language expressions when the expression needs to refer to the ViewModel and its state rather than to a rendered model object. |
vCurrent_Root
|
The current object at the root level. | In a rooted ViewModel, it identifies the root object. |
vClientScreenWidthvClientScreenHeight
|
The client viewport width and height, set by the Turnkey Angular client when the corresponding variables exist in the ViewModel. | Use a width value to choose ViewModel behavior based on the available viewport size. |
vIsMobileDevice
|
Indicates whether the client is regarded as a mobile device when the variable is defined. | Use it to make a ViewModel expression aware of the client device type. |
See Documentation:VClientScreenWidth and Documentation:VClientScreenHeight for the viewport variables.
Use vCurrent, vSelected, and self correctly
vCurrent is global to its named nesting
vCurrent_<NestingName> always means the currently focused object for that named nesting. It does not change while the server iterates through another list.
For example, assume a ViewModel shows Years, Months, and Days. If the user focused 2015, vCurrent_AllYear evaluates to 2015 everywhere it is used. If you place that variable in an expression that runs once for each Year row, every row evaluates against 2015. This can cause unnecessary or incorrect branches to be built and sent to the client.
Use vCurrent_* when you intentionally need a list to depend on a user's focus in another nesting. Do not use it as a replacement for the object currently being rendered in each row. For the complete master-detail explanation and client-tree consequences, see Documentation:How to use vCurrent and âselfâ correctly in viewmodels.
self depends on where the expression is evaluated
self is local to the ViewModel class where an expression is evaluated. In a detail ViewModel class, it refers to the detail object being rendered. In an expression on the green root ViewModel class, it refers to the root object.
This difference matters in a nested list:
- Use
selfto navigate from each object in the list currently being rendered. - Use
vCurrent_<NestingName>to navigate from the one object the user focused in the named list.
ViewModel actions act on one view rather than on the objects of a model class. In an action, use the applicable vCurrent_* or vSelected_* variable to identify the object or objects the action should handle.
vSelected is for multi-select
When a grid permits multi-select, MDriven maintains vSelected_<NestingName> as a collection. The collection is strongly typed to match the nesting.
For example, if a user selects three rows in an Order grid, an action can use vSelected_Order to process those three Orders. If the action should process only the row the user last clicked, use vCurrent_Order instead.
In WebUI DataGrids, a list without MultiSelect automatically selects its first row. With MultiSelect, the default is not to automatically select the first row. Set Nesting.AutoSelectFirstRow explicitly to true or false when the initial focus must be predictable. Read Documentation:VCurrent and vSelected for cursor and selection behavior.
Rooted ViewModels
A rooted ViewModel starts from a specific model object. In that situation, the root's current variable points at that root object and does not change as a user clicks objects in nested lists.
For example, if a rooted ViewModel is opened for one Thing, vCurrent_ViewOneThing points to that Thing for the lifetime of that ViewModel instance. At the root level, this is equivalent to self; in a nested ViewModel class, self instead refers to the object rendered by that nested class.
For the difference between rooted and unrooted ViewModels, see Documentation:ViewModel.
Define your own variables
Declare your own variable when the ViewModel must retain a value that is not supplied by the framework.
For example, you can declare a variable to retain a reference to an object the user is working with, then use that variable from later expressions or actions in the same ViewModel.
Choose a type that matches the value you intend to retain. Do not assume that cursor variables are useful in every execution context:
- In UI ViewModels,
vCurrent_*andvSelected_*represent user focus and selection. - In reports, no user interaction is available, so cursor variables are generally not used.
- In API scenarios, cursor variables can be used in special cases while processing imported JSON or XML, but they are not normally the primary mechanism.
For environment-specific values used by server-side jobs, use Documentation:Server Wide Variables rather than duplicating server configuration in each ViewModel.
Initialize a variable
An initial value is a value, not an expression. Enter only a literal that is compatible with the variable's declared type.
For example, do not use an expression as the initial value of a variable such as KundId. Also ensure that text which can be interpreted as a date, such as 1-1-1 or #1-1-1, is not used as the initial value for a variable of an incompatible type. Model checking does not currently warn about this invalid initialization.
When the initial value must be calculated, initialize it in an action instead:
- Create an initialization action that runs once, such as a periodic action configured to run once.
- Set the variable in that action using the required expression.
- Alternatively, set it in the OnShow expression of the action that navigates to the ViewModel.
Variables supplied by specific actions
Some actions provide additional variables only for a particular action context. For example, an action that opens a modal dialog can make specially named result variables available to the action that runs after the modal dialog closes.
Do not rely on such variables outside the action context that supplies them. Open the relevant action editor to see the variables available for that action.
Find the variables available in an expression
The editor is the authoritative way to check what you can use at a specific location.
- Open the OCL editor for the attribute or expression you are editing, or open the Action Editor for an in-view action.
- Inspect the methods and variables listed on the right-hand side of the editor.
- Select variables appropriate to the ViewModel class and action context. In particular, verify the nesting suffix of every
vCurrent_*andvSelected_*variable.
