Four mistakes, running
Each panel below is a real mistake, bound for real. The console panel underneath is the library's own output, captured as this demo bound - the same lines you would see in your browser's developer tools.
data-if="show"
If you can read this, the binding failed open.
Never shown - the bare observable reads as empty.
data-if="show.value"
Shown, because show.value is true.
data-bind-text="name.toUpperCase()"
Server text, left alone
A method call will not parse, so this one binding is skipped - the rest of the page carries on.
<!-- dm if --> inside a virtual list
- {{name}}: nested virtual if{{#if flag}}mustache if in the body{{/if}}
The nested comment block is left out of every row; the mustache #if block, scoped to the item, is the spelling that works.
<div class="demo-stage">
<div class="demo-controls">
<button class="btn btn-primary btn-sm" data-on-click="toggle">Toggle show</button>
<span class="demo-note">show.value is <strong data-bind-text="show.value ? 'true' : 'false'">false</strong></span>
</div>
<div class="rx-split">
<div class="rx-pane">
<code class="rx-pane-label">data-if="show"</code>
<p class="rx-pane-body" data-if="show">If you can read this, the binding failed open.</p>
<p class="demo-empty">Never shown - the bare observable reads as empty.</p>
</div>
<div class="rx-pane">
<code class="rx-pane-label">data-if="show.value"</code>
<p class="rx-pane-body" data-if="show.value">Shown, because show.value is true.</p>
</div>
<div class="rx-pane">
<code class="rx-pane-label">data-bind-text="name.toUpperCase()"</code>
<p class="rx-pane-body"><span data-bind-text="name.toUpperCase()">Server text, left alone</span></p>
<p class="demo-empty">A method call will not parse, so this one binding is skipped - the rest of the page carries on.</p>
</div>
<div class="rx-pane">
<code class="rx-pane-label"><!-- dm if --> inside a virtual list</code>
<ul class="demo-list">
<!-- dm each: items key=id -->
<li>{{name}}: <!-- dm if: flag --><b>nested virtual if</b><!-- /dm -->{{#if flag}}<b>mustache if in the body</b>{{/if}}</li>
<!-- /dm -->
</ul>
<p class="demo-empty">The nested comment block is left out of every row; the mustache <code>#if</code> block, scoped to the item, is the spelling that works.</p>
</div>
</div>
<div class="rx-console" aria-live="polite">
<div class="rx-console-bar">Console - captured from this demo</div>
<ol class="rx-console-lines" data-each="warnings key=id">
<li data-bind-text="text"></li>
</ol>
</div>
</div>/**
* Mistakes that fail closed, and say so.
*
* `data-if="show"` names the observable, not its value. Before 1.2 an
* observable object counted as true and the content showed; now it is read
* as empty and warns once, naming the fix. The warnings below are the real
* console output, captured as the page binds.
*/
function safety() {
const show = observable(false);
const warnings = observableArray([]);
const items = observableArray([
{id: 1, name: 'Row A', flag: false},
{id: 2, name: 'Row B', flag: true}
]);
return {
show, warnings, items,
name: 'ada',
toggle() { show.value = !show.peek(); }
};
}
/** Mirror the library's own console warnings into the demo's console panel. */
function captureWarnings(warnings) {
const original = console.warn;
let seq = 0;
console.warn = function (...args) {
const text = args.map((a) => (typeof a === 'string' ? a : String(a))).join(' ');
if (text.startsWith('[Domma Reactive]')) {
warnings.push({id: ++seq, text: text.replace('[Domma Reactive] ', '')});
}
return original.apply(this, args);
};
}An observable is not its value (1.2)
data-if="show" names the observable object, not its value, and every object is truthy - so before 1.2 the content
rendered and nothing said why. Now a binding whose expression resolves to an observable, an observable array or a
computed warns once - "show" is an observable, not its value - use "show.value" - and reads it as empty:
data-ifand{{#if}}hide;data-bind-disabled,-hiddenand-checkedare off;- text and attributes are written as an empty string, never
[object Object]; - as an operand (
!show,count > 3) the whole expression reads as empty, so!showcannot flip open either.
There is deliberately no automatic unwrapping: one spelling, .value, everywhere.
Nested virtual blocks fail closed (1.2)
A <!-- dm if --> inside a <!-- dm each --> body is not read - that body is compiled as a template, and the compiler
knows mustache, not comments. Before 1.2 its content rendered in every row; now it is left out, with a warning pointing
at {{#if flag}}, which is scoped to the item and works.
One broken binding, one warning
Nothing in the binding layer throws on bad input. A malformed expression, a method call, an unknown component, a param with no component: each logs exactly one warning naming the expression and the template, and that binding alone is skipped.