# ui-bind reference: every command, option and attribute

> All the commands of ui-bind with what each one does, the options that control when it runs, and the attributes that choose the target element.

Framework: jcomponent20
Product: jComponent 20 (jcomponent@20)
Language: en
Content-SHA256: d7dd2942e0d87bb5a180224f41aef86edbd3df78da67e6f6a52dc048d81fa14a
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: jcomponent20@3fedd009a277f50fddc608b97afbec553b67c51b
Review: not-recorded

`<ui-bind>` is the element that applies **commands** to the DOM when the value of its path changes. This page lists what each command does, the options that decide *when* it runs and the attributes that choose *which element* it changes.

The format is `config="command:expression;command:expression"`. In an expression `value` is the value of the path and `element` (also `el`) is the element that is changed. A command can have a selector (`text .name:value` applies it to the elements `.name` inside) and `attr` takes the attribute name first (`attr title:value`).

## Commands that change the element

| Command | What it does |
|---|---|
| `text:expr` | sets the text; an empty value shows the `empty` text |
| `html:expr` | sets the inner HTML (escape it yourself) |
| `value:expr` | sets the value of a form control |
| `title:expr`, `href:expr`, `src:expr` | sets that attribute |
| `attr name:expr` | sets any attribute |
| `.class:expr` | adds the class when the expression is true and removes it when false |
| `show:expr` / `hide:expr` | adds or removes the class `hidden` |
| `visible:expr` / `invisible:expr` | adds or removes the class `invisible` (the element keeps its space) |
| `checked:expr` | checks or unchecks the `input` inside |
| `disabled:expr` / `enabled:expr` | disables or enables the controls inside (`input`, `select`, `textarea`, `button`) and the `ui-component` elements inside |
| `required:expr` | sets the `required` option of the `ui-component` elements inside (it does not touch a plain `input`) |
| `template` | renders the Tangular template of the element (see the template recipe) |
| `exec:path` / `refresh:path` | calls the function at that path with the value, the path and the element, for every `SET` of the path of the binder |

`show` and `hide` run first, then `visible` and `invisible`, and `text`, `html` and `template` run last, so that the visibility of the element is already known when the content is written. `text`, `html` and `template` are only written while the element is visible, unless `forcerender:true` is in the same config: then they are written even when the element is hidden.

## Options: when the commands run

| Option | What it does |
|---|---|
| `changes` | skips the update when the value is the same as the last one |
| `strict` | only runs when the path of the binder itself changed, not when a child path changed (`user.name` does not run a binder of `user`) |
| `track:a,b` | only runs when one of those paths changed (a binder of `user` that tracks `user.name` ignores `user.age`); it runs again for every `SET` of a tracked path, even with the same value |
| `once` | runs once and then the binder is removed |
| `check:path` | calls the function at that path with `(value, path, element)`; the commands only run when it returns true |
| `delay:ms` | waits that many milliseconds and renders once, even if the value changed several times meanwhile (100 when no value is given) |
| `empty:text` | the text shown instead of an empty value (`---` when no text is given) |
| `format:pattern` | formats the value of `text`, `html`, `value`, `attr`, `title`, `href` and `src` with `String.format` |
| `class:name` | adds that class to the `ui-bind` element once, after the first render |
| `assign:path` | stores the binder instance at that path |
| `helpers:path` | the object at that path provides the helpers of the template: with `helpers:hh` and `hh = { shout: fn }`, the template can use `{{ value | shout() }}` |

## Attributes: which element changes

By default the commands change the `ui-bind` element. These attributes pick another one:

- `element="#target"` any element of the page (a jQuery selector)
- `child=".inner"` an element inside the `ui-bind`
- `parent=".card"` the closest ancestor that matches

The path can start with `!` (`path="!user.nick"`): the binder then ignores the moments when the value is `null` or `undefined`. A command name can also start with `!` or `~`: the prefix is accepted and ignored, the command works as without it.

## Attribute commands

- **Use one attribute per command: write `title:value` and `alt:value` as two commands.**

```html public/index.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8" />
	<title>jComponent</title>
	<link rel="stylesheet" href="//cdn.componentator.com/spa.min@20.css" />
	<script src="//cdn.componentator.com/spa.min@20.js"></script>
</head>
<body>
	<ui-bind path="user.age" config="visible:value > 17" id="visible"><span>adult</span></ui-bind>
	<ui-bind path="user.age" config="invisible:value > 17" id="invisible"><span>minor</span></ui-bind>
	<ui-bind path="user.name" config="text:value;class:marked" id="classonce"></ui-bind>
	<ui-bind path="user.name" config="text:(window.counter_changes = (window.counter_changes || 0) + 1) && value;changes" id="changes"></ui-bind>
	<ui-bind path="user" config="text:(window.counter_strict = (window.counter_strict || 0) + 1);strict" id="strict"></ui-bind>
	<ui-bind path="user" config="text:value.name;track:user.name" id="track"></ui-bind>
	<ui-bind path="user.name" config="text:value;once" id="once"></ui-bind>
	<ui-bind path="user.name" config="text:value;check:isready" id="check"></ui-bind>
	<ui-bind path="user.name" config="exec:onname" id="exec"></ui-bind>
	<ui-bind path="user.name" config="text:value;assign:binders.main" id="assign"></ui-bind>
	<ui-bind path="!user.nick" config="text:value" id="notnull"></ui-bind>
	<ui-bind path="user.name" config="text:value" element="#target" id="element"></ui-bind>
	<div id="target"></div>
	<ui-bind path="user.name" config="text:value" child=".inner" id="child"><b class="inner"></b></ui-bind>
	<ui-bind path="user.name" config="text .a:value;text .b:value.toUpperCase()" id="selector"><i class="a"></i><i class="b"></i></ui-bind>
	<ui-bind path="user.name" config="show:false;text:value;forcerender:true" id="force"></ui-bind>
	<ui-bind path="user.name" config="show:false;text:value" id="noforce"></ui-bind>
	<ui-bind path="user.admin" config="required:value;disabled:!value" id="flags"><input type="text" /></ui-bind>
	<ui-bind path="user.admin" config="checked:value" id="checked"><input type="checkbox" /></ui-bind>

	<ui-bind path="user.name" config="title+alt:value" id="clone"></ui-bind>
	<ui-bind path="user" config="text:(window.counter_track = (window.counter_track || 0) + 1);track:user.name" id="track2"></ui-bind>
	<ui-bind path="user.name" config="template;helpers:hh" id="helpers"><script type="text/html"><b>{{ value | shout() }}</b></script></ui-bind>
	<ui-bind path="user.none" config="text:value;empty" id="emptydef"></ui-bind>
	<ui-bind path="user.name" config="focus"><input type="text" id="f1" /></ui-bind>
	<ui-bind path="user.name" config="!text:value" id="bang"></ui-bind>
	<ui-bind path="user.name" config="~text:value" id="tilde"></ui-bind>
	<ui-bind path="user.name" config="text:el.attr('id') + '/' + element.attr('id')" id="elvar"></ui-bind>
	<div class="card"><ui-bind path="user.name" config="attr data-n:value" parent=".card" id="parentbind"></ui-bind></div>

	<script>
		window.hh = { shout: s => String(s).toUpperCase() };
		window.isready = function(value, path, element) {
			return value !== 'blocked';
		};
		window.exec_log = [];
		window.onname = function() {
			window.exec_log.push(Array.prototype.slice.call(arguments).map(a => typeof a === 'object' ? (a && a.nodeType ? 'element' : a && a.path ? 'path' : 'object') : String(a)).join('|'));
		};
		SET('user', { name: 'Ann', age: 30, admin: false });
	</script>

</body>
</html>
```
