State management
TODO: rewrite completely
As "state" we denote any JavaScript object which represents data point of your app which should be persisted and/or displayed in UI. State is managed and propagated automatically. There is no requirement for creating any abstractions, functions, helpers to change and propagate, as long [TBD]. Example:
<script>
var a;
</script>
<input type="text" oninput="a=this.value" />
<p bind>a</p>
a
value is observed and rendered inside <p>
every time new value is assigned to a
.
Worth noting is that user can create multiple ObservableContexts
for multiple bindDOM
calls completely separated from each other and at will manually propagate changes between those contexts. There is no single global state. Internally, state is always passed as an argument, just like config
or environment
in metaES nodes interpreters.
Chaining observations
Consider:
<script>
var a, b;
</script>
<input type="text" oninput="a=this.value" />
<p bind>(b = a ? a.toUpperCase() : ''), a</p>
<p bind>b</p>
b
is never set directly by user action; it's changed as a consequence of a
change. Chained observations are not an explicitly designed, they are byproduct of ObservableContext nature. Currently there is no protection against circular chains.
As a reminder:
(b = a ? a.toUpperCase() : ""), a;
represents Sequence Expression, which evaluates all comma separated expressions in order and as result returns value of last expresssion.
More advanced example:
let metaFetch;
metaesEval(`path=>callcc(fetcher, path)`, fn => (metaFetch = fn), console.error, {
fetcher: (path, c, cerr) =>
fetch(path)
.then(d => d.json())
.then(c)
.catch(cerr),
callcc: callWithCurrentContinuation
});
document.body.appendChild(
bindDOM(
`
<div>
<script>
function get(path) {
loading = true;
let result = fetch(path);
loading = false;
return result;
}
</script>
<p if="loading">Loading...</p>
<ul>
<li for="let post of get(page).data.children" bind>post.data.title</li>
</ul>
</div>`,
console.log,
console.error,
{
page: "https://www.reddit.com/r/programming.json"
loading: false,
fetch: metaFetch
}
)
);
Here we reach out for HTTP resource and indicatie in UI loading state. get
is synchronous in context of application code, but asynchronous for browser.