QORMQORM v0.8.4 docs Get started

Example: Todo

Lists, text input, and array state. Source: examples/todo.

qorm run examples/todo

Type a task and add it; toggle tasks done. The list is data-bound to an array in state, so adding/toggling re-renders it.

The pieces

An input bound two-way to state, and an add button that invokes an action:

{ "type": "input", "id": "field", "binding": "inputValue", "placeholder": "New task…" }
{ "type": "button", "id": "add", "label": "Add",
  "onPress": { "type": "invoke", "name": "addTodo", "args": { "text": "{{state.inputValue}}" } } }

The add action appends an object to the array and clears the input (actions/addTodo.json):

{ "type": "action", "id": "addTodo", "steps": [
  { "type": "state.appendObject", "path": "items",
    "item": { "id": "{{ text }}", "text": "{{ text }}", "done": "{{ false }}" } },
  { "type": "state.set", "path": "inputValue", "value": "" }
] }

A data-bound list renders each item; {{item.*}} is the per-row scope:

{ "type": "list", "id": "items", "data": "{{ state.items }}",
  "renderItem": { "type": "row", "children": [
    { "type": "checkbox", "onChange": { "type": "invoke", "name": "toggleTodo", "args": { "id": "{{item.id}}" } } },
    { "type": "text", "text": "{{ item.text }}" }
  ] } }

The row template also sees its position — {{ index }} (0-based), plus the first and last flags — so numbering, zebra striping and "hide the divider on the last row" need no extra state:

{ "type": "list", "id": "items", "data": "{{ state.items }}", "separator": true,
  "renderItem": { "type": "row", "children": [
    { "type": "text", "text": "{{ index + 1 }}." },
    { "type": "text", "text": "{{ item.text }}" }
  ] } }

A summary line is one expression over the same array:

{ "type": "text", "text": "{{ count(state.items, \"it.done\") }} of {{ len(state.items) }} done" }

Format notes

template (not item); {{ item.* }} is visible only inside that template.

your own data is never shadowed.

onRefresh — see First scene.