Skip to content

Instantly share code, notes, and snippets.

@asolove
Created January 6, 2014 21:43
Show Gist options
  • Save asolove/8290306 to your computer and use it in GitHub Desktop.
Save asolove/8290306 to your computer and use it in GitHub Desktop.
Om polymorphic cursor
(def map-state { :layers [{:selected true :title "Layer One"}, {:selected false :title "Layer Two" }]})
; I want a way to write reusable components that take and update data from a cursor,
; where the parent decides how the data is calculated and updated.
(defn checkbox [checked]
(om/component
(dom/input {:type "checkbox" :checked checked
:onClick #(om/update! checked (not checked)})))
(defn layers [layers]
(om/build checkbox
(cursor/decorate
layers
(every? :selected layers)
(fn [value]
(map layers #(assoc % :selected value))))))
; (cursor/decorate cursor value update) takes a parent cursor, and creates
; a new cursor with the given value. When update is called on the new cursor,
; it transacts against the parent using the provided function
@swannodette
Copy link

I think you won't need anything beyond ITransact + specify.

(defn layers [layers]
  (om/build checkbox
    (specify layers
      ITransact
      (-transact [this ks f]
        ...))))

The limitation here is that -transact only applies to this specific cursor, not further cursors produced from this one. Not sure if this will actually be a problem in practice.

@asolove
Copy link
Author

asolove commented Jan 7, 2014

That gives the component a cursor with all the data, rather than just the true/false that a reusable checkbox component would expect. The problem I'm thinking of is: what happens when you have two components that want to display the same data, but expect it in different shapes? It's not a big deal as long as you're writing custom app-specific components, but as soon as you have a reusable component library for things like form controls, autocomplete, validations, etc., we're going to run into this problem. The idea of having truly polymorphic cursors (completely independent of key-paths) is that a parent component can pass data in any shape to a child component, and provide a way for updates in the child to then be molded back into the shape the parent has. To make that happens, they need to be chainable: a zipper cursor based on the data output from a transformation cursor based on a zipper into the global state, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment