0

I will preface this question by saying I am still very much a novice when it comes to Clojure/Script, so besides the very pointed question I will pose any general feedback about style, usage would be greatly appreciated.

I have been building a very simple application with om.next. For client side routing I have decided to use Secretary. My application displays a list of items, and the intention is that when you click on one of those items you can view the details. The implementation at present is via a simple href on an anchor tag (e.g., an href might look like /items/1, where 1 is the id). This is partially because you should be able to navigate to the details URL directly to see the same view. As simple as this sounds, I cannot for the life of me get this to work as desired.

First, let's look at the salient configuration to the reconciler (for brevity I have removed the implementation details of component render throughout)...

(def init-data {:items [{:id 1
                         :title "stack overflow"
                         :description "hello, world."
                         :photos []}
                        {:id 2
                         :title "foo"
                         :description "bar"
                         :photos []}]})

(defui ListItem
  static om/Ident
  (ident [this {:keys [id]}]
    [:items/by-id id])
  static om/IQuery
  (query [this]
    [:id :title :description :photos]))

(defui Items
  static om/IQuery
  (query [this]
    [{:items (om/get-query ListItem)}]))

(defmulti read om/dispatch)

(defmethod read :items
  [{:keys [state query] :as env} key _]
  (let [st @state]
    {:value (om/db->tree query (get st key) st)}))

(def app-state (atom (om/tree->db Items init-data true)))

(def reconciler
  (om/reconciler {:parser (om/parser {:read read})
                  :state app-state}))

The astute will see that I am trying to think with links, and this much seems to be working as I would expect. It is when I add this component, and try to use it behind a Secretary route, that everything breaks down...

; I tried other approaches, they failed too
(defui Item
  static om/IQueryParams
  (params [this]
    {:id :not-found})
  static om/IQuery
  (query [this]
    '[[:items/by-id ?id]]))

(defn render-component [component]
  (let [app (gdom/getElement "app")]
    (doto reconciler
      (om/remove-root! app)
      (om/add-root! component app)))))

(defroute item-path "/items/:id" [id]
  (let [component Item]
    ; this is already less than ideal, as we know the id
    ; before the first render of the component
    (render-component component)
    (om/set-query! (om/class->any reconciler component)
                   {:id (js/parseInt id)})))

The instance of my Item component does not receive the proper state in props as specified in the query (it receives the entirety of app-state). What is most perplexing to me is that if I execute the same query against app-state manually in the REPL I get the right set of data back...

(get-in @app-state [:items/by-id 1])
; {:id 1, :title "stack overflow", :description "hello, world.", :photos []}

The only thing that has worked for me so far is to bypass the reconciler (creating the component instance myself), passing the query value from app-state as props. But that means I can't mutate state via the reconciler, which is a new horrific wrinkle to an otherwise messy, and unkempt conundrum.

What am I missing here? While I have many ideas, the thing I'm most suspicious about is the initialization of app-state via om/tree->db.

Colin Teal
  • 1
  • 1
  • 2
  • Have you tried passing in just `init-data` as `:state`? This quote from om.next wiki: "If not an atom the reconciler will normalize the data with the query supplied by the root component.": https://github.com/omcljs/om/wiki/Documentation-(om.next) – Chris Murphy Feb 10 '17 at 07:00
  • Thanks for the idea! I made that change alone (using `init-data` as a vector rather than an atom), and I get what looks like a reader error... `Uncaught Error: No method in multimethod 'items.core/read' for dispatch value: :items/by-id` ...which makes me think my problem may be that I need to write a special method to read `:items/by-id` (whether I make your suggested change, or not). – Colin Teal Feb 10 '17 at 17:52
  • I would stay away from links and give Items an ident - so structure it as if there is more than one of Items, even although there is in fact only one. – Chris Murphy Feb 10 '17 at 21:39

0 Answers0