You can use declarative ViewModels with optional placing hints to describe the data, behavior, relative layout, and tab sequence that a generated view can use; this is for developers maintaining ViewModels as their screens evolve.
Why make tab order declarative?
A ViewModel defines a perspective on the information in your model. It can support a user interface, an API, an export, or a report. For a user interface, the ViewModel describes the data to show and the rules that apply to it; optional placing hints add clues about how controls relate to one another.
Tab order is the keyboard-focus sequence between controls. It matters most on data-entry screens: users expect Tab to move through fields in the order in which they complete them. When a ViewModel changes over time, adding, removing, or moving fields can make that sequence difficult to understand unless it is visible in the ViewModel definition.
For example, a game setup screen may contain fields for a scheduled date, a home team, and a visitor team, followed by actions to start or end the game. A maintained tab sequence should let a keyboard user complete the date and team selections before moving to the relevant action. If a new field is inserted, review the sequence instead of leaving its position implicit.
Declarative ViewModels
A declarative ViewModel is a ViewModel in which you define the information and rules as named expressions rather than writing the user interface structure for every use. ViewModel classes can represent a root object and related collections. Expressions, including OCL expressions, define what each part contains and which values are available.
A rooted ViewModel starts from a specific model object. For example, a Game setup ViewModel can be rooted in one Game and show the teams and state-related actions for that Game. An unrooted ViewModel finds objects without receiving one specific root object, which is useful for searching. See Documentation:ViewModel for rooted and unrooted ViewModels.
When an expression needs the object currently being rendered, use self. When it needs the current object of a ViewModel class across the ViewModel, use the relevant vCurrent_<ViewModelClassName> variable. Choosing the wrong one can make rendering slow or return unexpected data; follow the guidance on vCurrent and self before changing expressions.
Use placing hints as layout clues
Placing hints are optional metadata on ViewModel columns. They can describe a control's intended relative placement, including its presentation, column, row, and span. A renderer may use these hints to generate a basic layout.
These hints do not make the ViewModel a presentation design. The ViewModel still defines the available data, valid values, and selection lists. The hints communicate the developer's intended arrangement to a UI designer or to a front end that can generate controls from them. External styles and templates remain responsible for the visual appearance of look-less controls.
| ViewModel concern | Example | Why it belongs in the ViewModel |
|---|---|---|
| Data available to the view | A Game's scheduled date, home team, and visitor team | The view needs a defined perspective on the model. |
| Valid values and selection lists | The home-team list is filtered by game type and excludes the selected visitor team | This is application behavior, not a visual styling decision. |
| State-dependent behavior | The Start action is available only after both teams are selected; the End action is unavailable until the game has started | The condition should remain consistent across user interfaces. |
| Optional placing hint | Put the scheduled date above the team selections, and let a selection span the intended columns | A renderer can create a basic relative layout without making the hint a fixed visual design. |
| Tab sequence | Move keyboard focus through date, home team, visitor team, and then the applicable action | The sequence is part of maintaining a usable data-entry flow. |
For a fuller example of a declarative GameSetup ViewModel and its rules, see Training:The declarative ViewModel. For the purpose and limits of placing hints, see Training:Taking It Further Still.
Maintain tab order as the ViewModel changes
Treat the visible tab sequence as a reviewable part of the ViewModel definition. Do this whenever you add, remove, rename, or reposition a field or action.
- Identify the data-entry path a keyboard user follows. Start with the first value the user must provide and end with the action that completes the task.
- Review the ViewModel columns and actions in that path. Confirm that the intended relative placement and tab sequence agree. A control placed after another field should not unexpectedly receive focus before it.
- Check conditions that affect availability. For example, do not direct users to an action that remains unavailable until required selections have been made.
- If you add a field, place it deliberately in the data-entry sequence. For example, if a new required field belongs between ScheduledDate and HomeTeam, ensure that keyboard focus reaches it between those two fields.
- Preview or run the ViewModel in the applicable client and test the screen with the Tab key. Verify both normal entry and states where conditions disable an action or filter a selection list.
- Repeat the review after structural edits. Small incremental changes are the common reason a previously coherent sequence becomes difficult to use.
Example: keep a game setup flow coherent
Consider a ViewModel for setting up a hockey game. It exposes a scheduled date, a home-team pick list, a visitor-team pick list, and actions whose availability depends on the Game state.
A coherent keyboard flow can be reviewed as follows:
- Enter or select the scheduled date.
- Select the home team from the list filtered for the game's team type.
- Select the visitor team; the home-team and visitor-team lists must not allow the same team to be selected for both roles.
- Move to Start Game only when both teams are set.
- After the game is started, make End Game available according to the Game state.
The exact appearance of these controls can vary by client and style. The ViewModel's responsibility is to keep its data, selections, conditions, placing hints, and maintained tab sequence understandable as one definition.
Keep responsibilities separate
Do not move application rules into client-specific UI code when they can be expressed in the ViewModel. For example, the filtering that prevents a selected visitor team from appearing as a possible home team is a ViewModel rule. A color, font, or visual template for the pick list is presentation and belongs outside the ViewModel.
Likewise, use placing hints and tab-order information to communicate structure, not to recreate a complete visual design. This lets generated or separately designed user interfaces use the same ViewModel behavior.
If actions navigate between several ViewModels, review that navigation separately with Documentation:Actions And Viewmodels, MDriven Designer. If an expression needs to refer to a ViewModel by name, use the ViewModels OCL operator rather than a string so that a ViewModel rename is detected by model validation.
