Here is a simple user interface component:
Here is the exact same interface component again peeking under the blindfold:
Clicking on the checkboxes should convince you that they are backed by the same data. Note that in the second case you can edit the EDN representation of the user interface and see corresponding changes.
It bears repeating that both examples are actually exactly the same:
(defn radio-button [data owner]
(reify
om/IRender
(render [_]
(dom/div #js {:className "radio"}
(dom/input
#js {:type "checkbox"
:checked (:checked data)
:onChange (fn [e]
(om/transact! data :checked not)
(om/transact! data :count inc))})
(dom/label nil (:label data))))))
(defn all-buttons [data owner]
(reify
om/IRender
(render [_]
(apply dom/div nil
(om/build-all radio-button (:ui data))))))
Then how are we getting the editing interface? Om now supports a very useful notion called instrumenting which allows us to peek under the blindfold without changing any of the original code.
The first example is rendered with the following:
(om/root all-buttons app-state
{:target (.getElementById js/document "ex0")})
The second example is rendered with the following:
(om/root all-buttons app-state
{:target (.getElementById js/document "ex1")
:instrument
(fn [f cursor m]
(if (= f radio-button)
(om/build* editor (om/graft [f cursor m] cursor))
::om/pass))})
The new :instrument
option of om.core/root
lets us intercept all
calls to om.core/build
so that we can instrument the user
interface without having to actually change it directly.
I suspect :instrument
will allow us to build a useful universe of
meta components that help us see more clearly.