Error: No queries exists for component path?

163 views Asked by At

I'm trying out om.next, trying to extend the example given in Components, Identity & Normalization.

The code in the example linked above contains of two lists that are backed by data in two different paths in the state. The example shows how the normalization of the data makes it possible to easily update normalized entities occurring in different views. In the code below I have removed the second list in the example below, since the behaviour shows up anyway.

Working example

The example below works and shows:

List A

  • John, points: 4 +
  • Mary, points: 0 +
  • Bob, points: 0 +

where the + is a button that increases the point for the person.

(ns ui.core
  (:require [om.next :as om :refer-macros [defui]]
            [om.dom :as dom]
            [goog.dom :as gdom]))

(def init-data
  {:list/one [{:name "John" :points 0}
              {:name "Mary" :points 0}
              {:name "Bob"  :points 0}]})

;; -----------------------------------------------------------------------------
;; Parsing

(defmulti read om/dispatch)

(defn get-people [state key]
  (let [st @state]
    (into [] (map #(get-in st %)) (get st key))))

(defmethod read :list/one
  [{:keys [state] :as env} key params]
  {:value (get-people state key)})

(defmulti mutate om/dispatch)

(defmethod mutate 'points/increment
  [{:keys [state]} _ {:keys [name]}]
  {:action
   (fn []
     (swap! state update-in
            [:person/by-name name :points]
            inc))})

;; -----------------------------------------------------------------------------
;; Components

(defui Person
  static om/Ident
  (ident [this {:keys [name]}] [:person/by-name name])
  static om/IQuery
  (query [this] '[:name :points :age])
  Object
  (render [this]
          (let [{:keys [points name] :as props} (om/props this)]
            (dom/li nil
                    (dom/label nil (str name ", points: " points))
                    (dom/button
                     #js {:onClick
                          (fn [e]
                            (om/transact! this
                                          `[(points/increment ~props)]))}
                     "+")))))

(def person (om/factory Person {:keyfn :name}))

(defui ListView
  Object
  (render [this]
          (let [list (om/props this)]
            (apply dom/ul nil
                   (map person list)))))

(def list-view (om/factory ListView {:key-fn ffirst}))

(defui RootView
  static om/IQuery
  (query [this]
         (let [subquery (om/get-query Person)]
           `[{:list/one ~subquery}]))
  Object
  (render [this]
          (let [{:keys [list/one]} (om/props this)]
            (apply dom/div nil
                   [
                    (dom/h2 nil "List A")
                    (list-view one)
                    ]))))

(def rootview (om/factory RootView))

;; wrapping the Root in another root (this fails)

(defui AnotherRoot
  static om/IQuery
  (query [this] `[~@(om/get-query RootView)])
  Object
  (render
   [this]
   (dom/div nil
            (rootview (om/props this)))))

(def reconciler
  (om/reconciler
   {:state  init-data
    :parser (om/parser {:read read :mutate mutate}) }))

(om/add-root! reconciler RootView (gdom/getElement "app"))

Problem: Using AnotherRoot as root component

However, when I change RootView in the last row to AnotherRoot, like:

(om/add-root! reconciler AnotherRoot (gdom/getElement "app"))

the ui still renders, but when pressing a button, the following error occurs:

Error: No queries exist for component path
(ui.core/AnotherRoot ui.core/RootView ui.core/Person)

The error comes from (next.cljc:1916)

I don't understand the error. The query from AnotherRoot returns the same query as RootView (however, you'll get a warning when returning the query straight away - which makes sense), but the reconciler seems to not be able to figure out how to re-render the component when the app-state changes.

The relevant dependencies should be:

[[org.clojure/clojure "1.9.0-alpha14"]
 [org.clojure/clojurescript "1.9.473"]                
 [figwheel-sidecar "0.5.9"]
 [org.omcljs/om "1.0.0-alpha47"]]

The question

What is the general way to create nested components in om.next?

0

There are 0 answers