Data Binding¶
RmlUi’s data binding keeps a document in sync with application state without
any element look-ups: the markup refers to named variables, and the library
re-evaluates the affected parts of the DOM when a variable is marked dirty.
The acron.rmlui module backs those variables with Python callables.
A data model is created on the context and must exist before any document that refers to it is loaded:
state = {"name": "Player One", "hp": 80, "items": ["axe", "rope"]}
model = context.create_data_model("hud")
model.bind_func("name", lambda: state["name"])
model.bind_func("hp", lambda: state["hp"],
lambda value: state.__setitem__("hp", int(value)))
model.bind_list("items", lambda: state["items"])
model.bind_event_callback("use", lambda index: use_item(int(index)))
doc = context.load_document("ui/hud.rml")
doc.show()
The document names the model on an element and uses the variables below it:
<div data-model="hud">
<p>{{ name }} - {{ hp }} hp</p>
<input type="range" min="0" max="100" data-value="hp"/>
<ul>
<li data-for="item, i : items" data-event-click="use(i)">{{ item }}</li>
</ul>
<p data-if="items.size == 0">Inventory empty.</p>
</div>
Kinds of binding¶
RmlDataModel.bind_func()A scalar variable (
bool,int,floatorstr) read through a getter, and optionally written through a setter when the document changes it (data-valueon a form control,data-checked, …).RmlDataModel.bind_list()A list of scalars for
data-for. The getter returns the whole list;{{ items.size }}reads its length.RmlDataModel.bind_dict_list()A list of records, each a
dictof scalars, fordata-forwith per-field access:data-for="row : rows"then{{ row.name }},data-if="row.visible"and so on.RmlDataModel.bind_event_callback()A callable for
data-event-<name>attributes. The arguments written in the expression are converted from RmlUi’s variants and passed positionally, sodata-event-click="join(host, port)"callsjoin(host, port)with the variables’ current values.
Each name can be bound once per model; the bind_* methods return False
for a name that is already taken.
Keeping the document current¶
Binding does not watch your Python objects. After changing state, tell the
model what changed with RmlDataModel.dirty_variable(), or
dirty_all() after a large update; the DOM is refreshed on
the context’s next update, which the region performs every frame.
state["items"].append("torch")
model.dirty_variable("items")
Data expressions have no escape sequences: inside a double-quoted attribute,
write string literals with single quotes, data-event-click="go('menu')".
Models are removed with RmlContext.remove_data_model(), and go away
with their context. A handle kept past that point is harmless – its methods
become no-ops – but RmlDataModel.is_valid() tells.