Skip to content

Instantly share code, notes, and snippets.

@ThomasDeutsch
Last active February 20, 2016 12:46
Show Gist options
  • Save ThomasDeutsch/0c1e8e4ac6627ce93ae5 to your computer and use it in GitHub Desktop.
Save ThomasDeutsch/0c1e8e4ac6627ce93ae5 to your computer and use it in GitHub Desktop.
(ns scheduler.devcards.omnexttest
(:require
[devcards.core]
[om.next :as om :refer-macros [defui ui]]
[om.dom :as dom :include-macros true])
(:require-macros
[devcards.core :as dc :refer [defcard defcard-doc defcard-om-next noframe-doc deftest dom-node]]))
(defcard-doc
"## Navigation with Toggle
With a click of a button (Nav component), you can select a movie.
The movie details will be shown (MovieDetails component).
If you click on a already selected movie, the movie-detais view will toggle.
In case no movie-details should be displayed, the reader will return `:not-found` and the
`mount->` function will not place the component in the roots render function.
### Problem: root gets rendered twice, in case a movie-details component will not be rendered.
open the console to see when the root gets rendered.
")
;; =====================================================================================================================
;; State
(def test-data (atom {:movie-by-id {"movie-1" {:id "movie-1"
:title "Pulp Fiction"
:year 1994}
"movie-2" {:id "movie-2"
:title "The Matrix"
:year 1999}}
:movies [[:movie-by-id "movie-1"]
[:movie-by-id "movie-2"]]
:selected-movie [:movie-by-id "movie-1"]}))
;; =====================================================================================================================
;; Helper fn
;; if reader returns :not-found, to not render a given component.
(defn mount-> [d component]
(if (= d :not-found)
nil
(component d)))
;; =====================================================================================================================
;; Mutate
(defmulti mutate om/dispatch)
(defmethod mutate 'movie/select
[{:keys [state]} _ {:keys [item-id]}]
{:action
(fn []
(let [st @state]
(if (= (second (:selected-movie st)) item-id)
(swap! state assoc-in [:selected-movie] nil)
(swap! state assoc-in [:selected-movie] [:movie-by-id item-id]))))})
;; =====================================================================================================================
;; Read
(defmulti read om/dispatch)
(defmethod read :nav
[{:keys [query state]} k _]
(let [st @state]
{:value (om/db->tree query (get st k) st)}))
(defmethod read :movie-details
[{:keys [query state]} k _]
(let [st @state]
{:value (if (some? (:selected-movie st))
(om/db->tree query (:selected-movie st) st)
:not-found)}))
;; =====================================================================================================================
;; Components
(defui ^:once Nav
static om/IQuery
(query [this]
'[[:movie-by-id _]
[:selected-movie _]])
Object
(render [this]
(let [{:keys [movie-by-id selected-movie]} (om/props this)]
(dom/ul #js{:className "item-list"}
(->> (vals movie-by-id)
(map (fn [item]
(dom/div nil
(dom/button #js{:style (if (= (:id selected-movie) (:id item)) #js{:backgroundColor "yellow"})
:onClick (fn [e] (om/transact! this `[(movie/select ~{:item-id (:id item)}) :selected-movie]))}
(:title item))))))))))
(def c-nav (om/factory Nav {}))
(defui ^:once MovieDetails
static om/IQuery
(query [this]
'[:title :year])
Object
(render [this]
(let [{:keys [title year]} (om/props this)]
(dom/h3 #js{:className "item-details"}
(dom/div nil "Title: " title)
(dom/div nil "Year: " year)))))
(def c-movie-details (om/factory MovieDetails {}))
(defui ^:once Root
static om/IQuery
(query [this]
[{:nav (om/get-query Nav)}
{:movie-details (om/get-query MovieDetails)}])
Object
(render [this]
(println "render root")
(let [{:keys [nav movie-details]} (om/props this)]
(dom/div nil
(mount-> nav c-nav) ;use of the mount-> helper function
(mount-> movie-details c-movie-details)))))
(defonce reconciler
(om/reconciler {:state test-data
:parser (om/parser {:read read
:mutate mutate})}))
(defcard navigation-with-toggle
(dc/om-next-root Root reconciler))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment