So here is an example of how to do "two way data-binding" in Hoplon. First you'd define a cell to hold the value:
(defc first-name nil)
Then, you'd connect up an
<input> element to it:
(defn event->val [ev] (.val (js/jQuery (.-target ev))))
:change (fn [ev] (reset! first-name (event->val ev)))
The value attribute of the
<input> element is bound to the
first-name cell. The element's on-change event fires a callback that updates the value in the cell, which then propagates to the value attribute of the input element.
Notice that this isn't true two way data binding, really. The only reactive binding is from the
first-name cell to the
value attribute of the input element. (The binding is strictly unidirectional.) The "other way" is handled by a callback which in this case changes the value in that cell. In other situations you may want it to do other things.
This is a nice separation of concerns because the callback doesn't necessarily need to know what
first-name is bound to, or what's watching it. It just mutates something somewhere, that's it. On the other end, the input element's
value attribute is bound to the cell, but there is no need to be concerned with how the cell is mutated or who mutates it or under which conditions.
However, the above is perhaps a little cumbersome. A lot of typing for a simple input element, right? So you can use
defelem to construct a
cell-input component with built-in data binding, like this:
(defelem cell-input [attrs children]
(let [state (:state attrs)
elem (input (dissoc attrs :state))]
:change (fn [ev] (reset! state (event->val ev))))))
You could then use that in your markup instead of regular input elements, like this:
(cell-input :type "text" :state first-name)
You can see that the final implementation needs no explicit DOM handling code, but it also is not in any way magical. It even presents an interface similar to what you'd find in a framework with two-way data binding, but there was no need to add anything to the language itself or to the framework, etc. Using Javelin and Hoplon, you can create this type of thing yourself with just a few lines of code, because you have the full power of Lisp at your fingertips.