Data views and controllers connect the document with the data in a given data model. Data views are used to present a data variable in the document by different means. On the other hand, data controllers are used to respond to changes in the document, typically as a result of user input. When a controller is triggered, it sets a data variable in its data model.

Data views and controllers are declared in the document by the element attribute:

data-[type]-[modifier]="[value]"

The modifier may or may not be required depending on the data view/controller. Some data bindings attach both a view and controller from the same attribute, enabling two-way bindings.

The following table lists all built-in data views and controllers in RmlUi, along with their declaration.

Name Type Attribute Value Notes
Attribute View data-attr-[attribute_name] [data_expression]  
Attribute-if View data-attrif-[attribute_name] [data_expression]  
Class View data-class-[class_name] [data_expression]  
Style View data-style-[property_name] [data_expression]  
If View data-if [data_expression]  
Visible View data-visible [data_expression]  
For View data-for [iterator_name], [index_name] : [data_address] [1]
Rml View data-rml [data_expression]  
Text View N/A N/A [2]
Alias View data-alias-[alias_name] [data_address]  
Value Two-way data-value [data_address] [3]
Checked Two-way data-checked [data_address] [3]
Event Controller data-event-[event_type] [assignment_expression]  

[1] iterator_name and index_name are optional. Defaults to it and it_index, respectively.
[2] The text view is automatically added whenever double curly brackets {{ }} are encountered in the element’s text.
[3] These attributes enable two-way bindings, and will attach both a view and controller to the element.

When data views are updated, their data expressions are evaluated and applied to the document using any necessary type conversion, which is specified by the kind of the data view. Type conversion is done using RmlUi’s built-in TypeConverter utilities. One aspect of this conversion is that booleans are converted to strings "0" or "1". Consider an element

<div data-attr-foo="user_data"></div>

where the value user_data is bound to a C++ variable bool user_data = true. The element’s attribute will be set to foo="1". Any associated RCSS attribute selector should use the same representation of the value, i.e. div[foo=1].

Attribute

data-attr-[attribute_name]="[data_expression]"

Sets the element’s attribute [attribute_name] to the evaluated expression.

<img data-attr-sprite="item.icon"/>

Attribute-if

data-attrif-[attribute_name]="[data_expression]"

Sets the element’s attribute [attribute_name] when the expression evaluates to true, otherwise removes the given attribute from the element.

<input type="checkbox" name="meals" value="pizza" data-attrif-disabled="rating > 70"/>

Useful for element behavior which depends on whether or not the attribute is present, such as disabled. When set, the value of the attribute is an empty string.

Class

data-class-[class_name]="[data_expression]"

Enables the class [class_name] on the element if the expression evaluates to true, otherwise it disables the class.

<h1 data-class-red="score < 30">Score</h1>

Style

data-style-[property_name]="[data_expression]"

Sets the property [property_name] of the element’s style to the evaluated expression.

<img sprite="invader" data-style-image-color="invader.color"/>

If

data-if="[data_expression]"

Sets the display property of the element to none if the expression evaluates to false, otherwise it removes the display property from the element’s inline style.

<div data-if="rating > 50">
	Thanks for the <span data-if="rating >= 80">awesome</span> rating!
</div>

Note. The style sheet rules which applies to the element should ensure that the element’s display property evaluates to something other than none. Otherwise, the element will always be hidden.

Visible

data-visible="[data_expression]"

Sets the visibility property of the element to hidden if the expression evaluates to false, otherwise it removes the visibility property from the element’s inline style.

<div data-visible="collected_stars > 0">
	<img sprite="star"/>
</div>

As opposed to the data-if view, the data-visible view ensures that the element retains it’s size regardless of visibility.

Note. The style sheet rules which applies to the element should ensure that the element’s visibility property evaluates to visible, which is the default value. Otherwise, the element will always be hidden.

For

data-for="[iterator_name], [index_name] : [data_address]"

Repeats the element and its children n times for each item in the data variable designated by the data_address. The variable must be a data array type.

<div data-for="invader : invaders">
	<h1>{{ invader.name }}</h1>
	<p>Invader {{it_index + 1}} of {{ invaders.size }}.</p>
	<img data-attr-sprite="invader.sprite" data-style-image-color="invader.color"/>
	<p>Scores: <span data-for="invader.scores"> {{it}} </span></p>
</div>

An iterator can be used to retrieve values from the current item in the data array.

The data-for attribute can use any of the following values, enabling the user to override the default iterator and index names if desired. Note that the index is zero-based.

Attribute value Iterator name Index name
[data_address] it it_index
[iterator_name] : [data_address] [iterator_name] it_index
[iterator_name], [index_name] : [data_address] [iterator_name] [index_name]

The data-for loop is expanded by replicating the element with its attributes and its inner RML, for each entry in the array. Eg.

<p data-for="subject, i : subjects" data-class-selected="i == selected_subject">{{i + ': ' + subject}}</p>

with three entries in subjects is turned into

<p data-class-selected="i == selected_subject">{{i + ': ' + subject}}</p>
<p data-class-selected="i == selected_subject">{{i + ': ' + subject}}</p>
<p data-class-selected="i == selected_subject">{{i + ': ' + subject}}</p>
<p style="display: none;"/>

where i and subject become aliases to the array index and entry, respectively. Additionally, an element is added after all the entries so that the location of the for loop within the document tree is well defined even when there are no entries. This will become hidden by the display: none inline style added by the data view.

Note. For performance reasons the names of global data variables shadow iterator names. Thus, do not use an iterator name which is used for a data binding.
Implementation note. Internally, the XML parser uses a special parsing rule whenever the data-for attribute is encountered, providing all the children of the current element as raw RML text to the data view, which is later used for creation of each item in the data array.

Rml

data-rml="[data_expression]"

Sets the element’s inner RML to the evaluated expression.

<div data-rml="incoming_invaders ? '<em>Send help!</em>' : 'Clear skies.'">
</div>

Text

N/A

Evaluates any data expression inside double curly brackets {{ }} encountered in the element’s text.

<span class="position"> x: {{ position.x }}, y: {{ position.y }}</span>
<span data-for="i : indices"> {{ i * 2 + (i > 10 ? ' wow!' | to_upper : '') }}</span>

This data view is automatically added whenever double curly brackets are encountered in the text and should not be added as an attribute.

Alias

data-alias-[alias_name]="[data_address]"

Creates a new alias variable at the given scope, allowing the stated data address to be referred to by its alias name.

This allows templates to be used as reusable components within data models. By wrapping the inline template in an element that defines variable name aliases, the template can refer to any outside variable by a fixed name.

To illustrate, consider the following template.

<template name="data-title">
<head></head>
<body>
	<div class="icon" data-attr-icon="icon"></div>
	<h1 class="title">{{ title }}</h1>
</body>
</template>

This template can then be used with different variables as follows:

<div data-alias-title="t0" data-alias-icon="i0">
	<template src="data-title"/>
</div>
<div data-alias-title="t1" data-alias-icon="i1">
	<template src="data-title"/>
</div>

Value

data-value="[data_address]"

Synchronizes the element’s value attribute to the value of the data variable located at data_address. This variable must be a scalar type. This is generally useful for input elements.

<input type="range" min="0" max="100" step="1" data-value="rating"/>

A new value is assigned to the specified data variable whenever a change event occurs on the current element. The element’s value attribute is updated whenever the data variable changes on the client side.

Note. Data expressions and assignment expressions are not supported for this attribute. Instead, use the data-attr-value view and data-event-change controller for more flexibility.

Checked

data-checked="[data_address]"

Binds a checkbox or radio button’s checked state to the variable located at data_address. This variable must be a scalar type. Typically combined with <input type="checkbox"/> and <input type="radio"/> elements.

<input type="radio" name="animal" value="dog" data-checked="animal"/> Dog
<input type="radio" name="animal" value="cat" data-checked="animal"/> Cat
<input type="checkbox" name="meals" value="pasta" data-checked="pasta"/> Pasta

For checkboxes, the underlying data type should be a bool, where true means checked and false means unchecked. For radio buttons, the underlying type should be an Rml::String type where its value corresponds to the value attribute of the currently selected radio button.

A new value is assigned to the specified data variable whenever a change event occurs on the current element. The element’s checked attribute is added or removed whenever the data variable changes on the client side.

Note. Data expressions and assignment expressions are not supported for this attribute. Instead, use the data-attrif-checked view and data-event-change controller for more flexibility.

Event

data-event-[event_type]="[assignment_expression]"

The event controller is triggered whenever the [event_type] event occurs on the current element. All event types in RmlUi are supported. Upon triggering, the associated assignment expression is evaluated.

An assignment expression is specified as one of the following two statements.

(1) [data_address] = [data_expression]
(2) [event_callback_name]([data_expression], [data_expression], ...)

Furthermore, a single assignment expression can take multiple such statements by semicolon-separating them.

In (1), the data variable associated with the address on the left hand side is assigned the evaluated expression on the right hand side. Only scalar types can be assigned to.

In (2), the given event callback is called in C++, with the triggering event itself, a handle to the current data model, and the list of parameters inside the parenthesis.

The special variable ev can be used inside the expressions to retrieve values from the triggering event.

<div class="mouse_detector"
	data-event-mousemove="mouse_detector = 'x: ' + ev.mouse_x + '<br/>y: ' + ev.mouse_y"
	data-event-click="add_mouse_pos(); hello_world = 'Hello click!'"
	data-rml="mouse_detector">
</div>
<h1>{{hello_world}}</h1>
<div data-for="positions">{{it}}</div>

The referenced add_mouse_pos event callback is triggered when the element is clicked, which can be implemented in C++ as follows.

using namespace Rml;

std::vector<Vector2f> positions;

void AddMousePos(DataModelHandle model_handle, Event& ev, const VariantList& arguments)
{
	positions.emplace_back(ev.GetParameter("mouse_x", 0.f), ev.GetParameter("mouse_y", 0.f));
	model_handle.DirtyVariable("positions");
}