Skip to content

Instantly share code, notes, and snippets.

@IwanKaramazow
Created June 13, 2016 07:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IwanKaramazow/115de05f35277754104f7eb47c06590c to your computer and use it in GitHub Desktop.
Save IwanKaramazow/115de05f35277754104f7eb47c06590c to your computer and use it in GitHub Desktop.
Working solution.cljs
(ns listdetail.core
(:require [goog.dom :as gdom]
[om.next :as om :refer-macros [defui]]
[om.dom :as dom]
[clojure.set :as set]))
(enable-console-print!)
(def app-state {})
(defmulti read om/dispatch)
(defmethod read :projects
[{:keys [state ast query query-root]} k _]
(let [st @state]
(if-let [x (get-in st [:active-props k])]
{:value (om/db->tree query x st)}
{:remote (assoc ast :query-root true)})))
(defmethod read :project/detail
[{:keys [ast state query target]} key {:keys [id]}]
(let [st @state
id (if id id (:project/selected st))]
(when id
(let [val (om/db->tree query [:project/by-id id] st)
available (keys val)
diffed-query (->
(into [] (set/difference (set query) (set available)))
(conj :id))]
(if (= available query)
{:value val}
{:value val
:remote (-> ast
(assoc :query diffed-query)
(assoc :query-root true)) })))))
(defmulti mutate om/dispatch)
(defmethod mutate 'project/select
[{:keys [state]} key {:keys [id]}]
{:action #(swap! state assoc :project/selected id)})
(defmethod read :active-props
[{:keys [parser query ast target] :as env} key _]
(let [remote (parser env query target)]
(if (and target (not-empty remote))
{:remote (update-in ast [:query] (fn [query] remote))}
{:value (parser env query)})))
;; components
(defui ProjectListItem
static om/Ident
(ident [this {:keys [id]}]
[:project/by-id id])
static om/IQuery
(query [_]
[:id :title])
Object
(render [this]
(let [{:keys [id title]} (om/props this)
{:keys [select] } (om/get-computed this)]
(dom/li #js {:onClick (fn [e]
(select id))} title))))
(def projectListItem (om/factory ProjectListItem))
(defn project-list [projects select]
(dom/div nil
(dom/h3 nil "Project list:")
(dom/ul nil
(map #(projectListItem (om/computed % {:select select})) projects))))
(defui ProjectDetail
static om/Ident
(ident [this {:keys [id]}]
[:project/by-id id])
static om/IQuery
(query [_]
[:id :title :description])
Object
(render [this]
(let [{:keys [id title description]} (om/props this)]
(dom/div nil
(dom/h3 nil "Project Detail")
(if (nil? id)
(dom/div nil "No project selected.")
(dom/div nil
(dom/div nil "Selected project: " id)
(dom/div nil "Title: " title)
(dom/div nil "Description: " description)))))))
(def project-detail (om/factory ProjectDetail))
(defn select-project [component]
(fn [id]
(om/transact! component `[(project/select {:id ~id})])
(om/update-query! component
(fn [{:keys [query params] :as q}]
(update q :params assoc :id id)) )))
(defui Wrapper
static om/IQueryParams
(params [this]
{:id nil})
static om/IQuery
(query [_]
`[{:projects ~(om/get-query ProjectListItem)}
({:project/detail ~(om/get-query ProjectDetail)} {:id ~'?id})])
Object
(render [this]
(let [{:keys [projects project/detail]} (om/props this)]
(dom/div nil
(project-list projects (select-project this))
(project-detail detail)))))
(def wrapper (om/factory Wrapper))
(defui Root
static om/IQueryParams
(params
[this]
{:active-query []})
static om/IQuery
(query
[this]
'[{:active-props ?active-query}])
Object
(componentWillMount
[this]
(om/set-query! this
{:params {:active-query (om/get-query Wrapper)}}))
(render
[this]
(let [{:keys [active-props] :as props} (om/props this)]
(dom/div {} (wrapper active-props)))))
;; fake backend
(def fake-database (atom {:projects [[:project/by-id 1] [:project/by-id 2]], :project/by-id {1 {:id 1, :title "Learn Haskell" :description "How do I get started with Haskell?"}, 2 {:id 2, :title "Learn Scheme" :description "Lisp rocks!"}}}))
(defmulti backend-read om/dispatch)
(defmethod backend-read :projects
[{:keys [database query]} key {:keys [id]}]
(let [db @database]
{:value (om/db->tree query (:projects db) db)}))
(defmethod backend-read :project/detail
[{:keys [database query]} key {:keys [id]}]
(let [db @database]
{:value (om/db->tree query [:project/by-id id] db)}))
(def backend-parser (om/parser {:read backend-read}))
;; fake a send to the fake backend
(defn send [{:keys [remote]} merge]
(let [{:keys [query rewrite]} (om/process-roots remote)
_ (println "incoming query" query)]
(merge (rewrite (backend-parser {:database fake-database} query)))))
;; do not throw away the app state when merging
(defn deep-merge [& xs]
"Merges nested maps without overwriting existing keys."
(if (every? map? xs)
(apply merge-with deep-merge xs)
(last xs)))
;;reconciler
(def reconciler
(om/reconciler
{:state app-state
:parser (om/parser {:read read :mutate mutate})
:send send
:merge-tree deep-merge}))
(om/add-root! reconciler
Root (gdom/getElement "app"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment