Update local state directly with om cursors
This commit is contained in:
parent
5230dc9601
commit
11597a9b63
6 changed files with 106 additions and 131 deletions
|
@ -66,13 +66,11 @@
|
|||
(assoc state :recipes (dissoc (:recipes state) (:id event))))
|
||||
|
||||
(defn update-state-and-render [remote]
|
||||
(let [out (chan)
|
||||
view-events (view/render-app app-state)]
|
||||
(view/render-app app-state)
|
||||
(let [out (chan)]
|
||||
(go-loop []
|
||||
(let [[event ch] (alts! [remote view-events])
|
||||
(let [event (<! remote)
|
||||
new-state (handle-event event @app-state)]
|
||||
(reset! app-state new-state)
|
||||
(when (= ch view-events)
|
||||
(>! out event))
|
||||
(recur)))
|
||||
out))
|
||||
|
|
|
@ -26,29 +26,12 @@
|
|||
(dom/on-window-scroll #(put! >events {:type :body-scroll :event %}))))))
|
||||
|
||||
(defn render-app [state]
|
||||
(let [grub-add (chan)
|
||||
grub-update (chan)
|
||||
grub-clear-all (chan)
|
||||
grub-remove (chan)
|
||||
recipe-add (chan)
|
||||
recipe-add-grubs (chan)
|
||||
recipe-update (chan)
|
||||
recipe-remove (chan)
|
||||
out (a/merge [grub-add grub-update grub-clear-all grub-remove
|
||||
recipe-add recipe-add-grubs recipe-update recipe-remove])
|
||||
>events (chan)
|
||||
<events (a/pub >events :type)]
|
||||
(let [>events (chan)
|
||||
<events (a/pub >events :type)
|
||||
add-grubs-ch (chan)]
|
||||
(om/root app-view
|
||||
state
|
||||
{:target (.getElementById js/document "container")
|
||||
:shared {:grub-add grub-add
|
||||
:grub-update grub-update
|
||||
:grub-clear-all grub-clear-all
|
||||
:grub-remove grub-remove
|
||||
:recipe-add recipe-add
|
||||
:recipe-add-grubs recipe-add-grubs
|
||||
:recipe-update recipe-update
|
||||
:recipe-remove recipe-remove
|
||||
:>events >events
|
||||
:<events <events}})
|
||||
out))
|
||||
:shared {:>events >events
|
||||
:<events <events
|
||||
:add-grubs-ch add-grubs-ch}})))
|
||||
|
|
|
@ -7,32 +7,11 @@
|
|||
(:require-macros [grub.macros :refer [log logs]]
|
||||
[cljs.core.async.macros :refer [go go-loop]]))
|
||||
|
||||
(defn new-grub [grub]
|
||||
(defn new-grub [text]
|
||||
{:id (str "grub-" (uuid/make-random))
|
||||
:grub grub
|
||||
:text text
|
||||
:completed false})
|
||||
|
||||
(defn add-event [grub]
|
||||
(assoc (new-grub grub) :event :add-grub))
|
||||
|
||||
(defn add-list-event [grubs]
|
||||
{:event :add-grub-list
|
||||
:grubs grubs})
|
||||
|
||||
(defn edit-event [id grub]
|
||||
{:event :update-grub
|
||||
:id id
|
||||
:grub grub})
|
||||
|
||||
(defn complete-event [{:keys [id completed]}]
|
||||
{:event :update-grub
|
||||
:id id
|
||||
:completed (not completed)})
|
||||
|
||||
(defn remove-event [id]
|
||||
{:event :remove-grub
|
||||
:id id})
|
||||
|
||||
(def transitions
|
||||
{:waiting {:mouse-down :pressed
|
||||
:touch-start :pressed}
|
||||
|
@ -54,21 +33,18 @@
|
|||
timeout-id (js/setTimeout timeout-fn 500)]
|
||||
(om/set-state! owner :timeout-id timeout-id))
|
||||
[:pressed :waiting] (js/clearTimeout (om/get-state owner :timeout-id))
|
||||
[:editing :waiting] (let [update-ch (om/get-shared owner :grub-update)
|
||||
id (:id @(om/get-props owner))
|
||||
edit-event (edit-event id (om/get-state owner :grub))]
|
||||
(put! update-ch edit-event))
|
||||
[:editing :waiting] (let [grub (om/get-props owner)]
|
||||
(om/transact! grub #(assoc % :text (om/get-state owner :grub-text))))
|
||||
nil)
|
||||
(om/set-state! owner :edit-state next)))
|
||||
|
||||
(defn view [{:keys [id grub completed] :as props} owner]
|
||||
(defn view [{:keys [id text completed] :as grub} owner {:keys [remove-ch]}]
|
||||
(reify
|
||||
om/IInitState
|
||||
(init-state [_]
|
||||
(let [publisher (chan)]
|
||||
{:edit-state :waiting
|
||||
:grub grub
|
||||
:unmounted false}))
|
||||
{:edit-state :waiting
|
||||
:grub-text text
|
||||
:unmounted false})
|
||||
|
||||
om/IRenderState
|
||||
(render-state [_ {:keys [edit-state] :as state}]
|
||||
|
@ -77,9 +53,9 @@
|
|||
{:class [(when completed "completed")
|
||||
(when (= edit-state :pressed) "grub-active")
|
||||
(when (= edit-state :editing) "edit")]
|
||||
:on-click #(when (#{:waiting :pressed} edit-state)
|
||||
(put! (om/get-shared owner :grub-update) (complete-event @props))
|
||||
(.blur (om/get-node owner :grub-input)))
|
||||
:on-click (fn [e] (when (#{:waiting :pressed} edit-state)
|
||||
(om/transact! grub #(assoc % :completed (not completed)))
|
||||
(.blur (om/get-node owner :grub-input))))
|
||||
:on-mouse-down #(transition-state owner :mouse-down)
|
||||
:on-mouse-up #(transition-state owner :mouse-up)
|
||||
:on-mouse-leave #(transition-state owner :mouse-leave)
|
||||
|
@ -90,12 +66,12 @@
|
|||
{:type "text"
|
||||
:readOnly (if (= edit-state :editing) "" "readonly")
|
||||
:ref :grub-input
|
||||
:value (:grub state)
|
||||
:on-change #(om/set-state! owner :grub (.. % -target -value))
|
||||
:value (:grub-text state)
|
||||
:on-change #(om/set-state! owner :grub-text (.. % -target -value))
|
||||
:on-key-up #(when (dom/enter-pressed? %) (transition-state owner :enter))}]
|
||||
(when (= edit-state :editing)
|
||||
[:span.glyphicon.glyphicon-remove.pull-right
|
||||
{:on-click #(put! (om/get-shared owner :grub-remove) (remove-event id))}])]))
|
||||
{:on-click #(put! remove-ch id)}])]))
|
||||
|
||||
om/IDidMount
|
||||
(did-mount [_]
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
(ns grub.view.grub-list
|
||||
(:require [om.core :as om :include-macros true]
|
||||
[sablono.core :as html :refer-macros [html]]
|
||||
[cljs.core.async :as a :refer [<! put! chan]]
|
||||
[cljs.core.async :as a :refer [<! chan]]
|
||||
[grub.view.dom :as dom]
|
||||
[grub.view.grub :as grub-view]
|
||||
[cljs-uuid.core :as uuid])
|
||||
[grub.view.grub :as grub-view])
|
||||
(:require-macros [grub.macros :refer [log logs]]
|
||||
[cljs.core.async.macros :refer [go go-loop]]))
|
||||
|
||||
|
@ -17,18 +16,20 @@
|
|||
(defn sort-grubs [grubs]
|
||||
(sort-by (juxt :completed get-grub-ingredient :grub) (vals grubs)))
|
||||
|
||||
(defn add-grub [add new-grub owner]
|
||||
(when (not (empty? new-grub))
|
||||
(om/set-state! owner :new-grub "")
|
||||
(put! add (grub-view/add-event new-grub))))
|
||||
(defn add-grub [owner grubs new-grub-text]
|
||||
(when (not (empty? new-grub-text))
|
||||
(let [new-grub (grub-view/new-grub new-grub-text)]
|
||||
(om/set-state! owner :new-grub-text "")
|
||||
(om/transact! grubs #(assoc % (:id new-grub) new-grub)))))
|
||||
|
||||
(defn view [props owner]
|
||||
(defn view [grubs owner]
|
||||
(reify
|
||||
om/IInitState
|
||||
(init-state [_]
|
||||
{:new-grub ""})
|
||||
{:new-grub-text ""
|
||||
:remove-grub-ch (chan)})
|
||||
om/IRenderState
|
||||
(render-state [this {:keys [new-grub] :as state}]
|
||||
(render-state [this {:keys [new-grub-text remove-grub-ch] :as state}]
|
||||
(let [add (om/get-shared owner :grub-add)]
|
||||
(html
|
||||
[:div
|
||||
|
@ -38,22 +39,35 @@
|
|||
[:input.form-control#add-grub-input
|
||||
{:type "text"
|
||||
:placeholder "What do you need?"
|
||||
:value new-grub
|
||||
:value new-grub-text
|
||||
:on-key-up #(when (dom/enter-pressed? %)
|
||||
(add-grub add new-grub owner))
|
||||
:on-change #(om/set-state! owner :new-grub (dom/event-val %))}]]
|
||||
(add-grub owner grubs new-grub-text))
|
||||
:on-change #(om/set-state! owner :new-grub-text (dom/event-val %))}]]
|
||||
[:button.btn.btn-primary
|
||||
{:id "add-grub-btn"
|
||||
:type "button"
|
||||
:on-click #(add-grub add new-grub owner)}
|
||||
:on-click #(add-grub owner grubs new-grub-text)}
|
||||
[:span.glyphicon.glyphicon-plus]]]
|
||||
[:ul#grub-list.list-group
|
||||
(for [grub (sort-grubs props)]
|
||||
(om/build grub-view/view grub {:key :id}))]
|
||||
(for [grub (sort-grubs grubs)]
|
||||
(om/build grub-view/view grub {:key :id :opts {:remove-ch remove-grub-ch}}))]
|
||||
[:button.btn.pull-right
|
||||
{:id "clear-all-btn"
|
||||
:class (when (empty? props) "hidden")
|
||||
:class (when (empty? grubs) "hidden")
|
||||
:type "button"
|
||||
:on-click #(put! (om/get-shared owner :grub-clear-all)
|
||||
{:event :clear-all-grubs})}
|
||||
"Clear all"]])))))
|
||||
:on-click #(om/update! grubs {})}
|
||||
"Clear all"]])))
|
||||
om/IWillMount
|
||||
(will-mount [_]
|
||||
(let [add-grubs-ch (om/get-shared owner :add-grubs-ch)
|
||||
remove-grub-ch (om/get-state owner :remove-grub-ch)]
|
||||
(go-loop []
|
||||
(let [grubs-map (<! add-grubs-ch)]
|
||||
(when-not (nil? grubs-map)
|
||||
(om/transact! grubs #(merge % grubs-map))
|
||||
(recur))))
|
||||
(go-loop []
|
||||
(let [id (<! remove-grub-ch)]
|
||||
(when-not (nil? id)
|
||||
(om/transact! grubs #(dissoc % id))
|
||||
(recur))))))))
|
||||
|
|
|
@ -8,32 +8,26 @@
|
|||
(:require-macros [grub.macros :refer [log logs]]
|
||||
[cljs.core.async.macros :refer [go go-loop]]))
|
||||
|
||||
(defn add-event [name grubs]
|
||||
{:event :add-recipe
|
||||
:id (str "recipe-" (uuid/make-random))
|
||||
(defn new-recipe [name grubs]
|
||||
{:id (str "recipe-" (uuid/make-random))
|
||||
:name name
|
||||
:grubs grubs})
|
||||
|
||||
(defn update-event [id name grubs]
|
||||
{:event :update-recipe
|
||||
:id id
|
||||
:name name
|
||||
:grubs grubs})
|
||||
|
||||
(defn remove-event [id]
|
||||
{:event :remove-recipe
|
||||
:id id})
|
||||
|
||||
(defn parse-grubs-from-str [grubs-str]
|
||||
(->> grubs-str
|
||||
(clojure.string/split-lines)
|
||||
(map grub-view/new-grub)
|
||||
(into [])))
|
||||
|
||||
(defn map-by-key [key coll]
|
||||
(->> coll
|
||||
(map (fn [a] [(get a key) a]))
|
||||
(into {})))
|
||||
|
||||
(defn add-grubs [add-grubs-ch grubs-str]
|
||||
(let [grubs (parse-grubs-from-str grubs-str)
|
||||
event (grub-view/add-list-event grubs)]
|
||||
(put! add-grubs-ch event)))
|
||||
grubs-map (map-by-key :id grubs)]
|
||||
(put! add-grubs-ch grubs-map)))
|
||||
|
||||
(def transitions
|
||||
{:waiting {:click :editing}
|
||||
|
@ -44,38 +38,35 @@
|
|||
(let [current (om/get-state owner :edit-state)
|
||||
next (or (get-in transitions [current event]) current)]
|
||||
(condp = [current next]
|
||||
[:editing :waiting] (let [update-ch (om/get-shared owner :recipe-update)
|
||||
id (:id @(om/get-props owner))
|
||||
[:editing :waiting] (let [recipe (om/get-props owner)
|
||||
name (om/get-state owner :name)
|
||||
|
||||
grubs (om/get-state owner :grubs)
|
||||
event (update-event id name grubs)]
|
||||
(put! update-ch event))
|
||||
grubs (om/get-state owner :grubs)]
|
||||
(om/transact! recipe #(assoc % :name name :grubs grubs)))
|
||||
nil)
|
||||
(om/set-state! owner :edit-state next)))
|
||||
|
||||
(defn num-newlines [str]
|
||||
(count (re-seq #"\n" str)))
|
||||
|
||||
(defn view [{:keys [id] :as props} owner]
|
||||
(defn view [{:keys [id] :as recipe} owner {:keys [remove-recipe-ch]}]
|
||||
(reify
|
||||
om/IInitState
|
||||
(init-state [_]
|
||||
(let [publisher (chan)]
|
||||
{:edit-state :waiting
|
||||
:name (:name props)
|
||||
:grubs (:grubs props)
|
||||
:name (:name recipe)
|
||||
:grubs (:grubs recipe)
|
||||
:unmounted false}))
|
||||
|
||||
om/IWillReceiveProps
|
||||
(will-receive-props [this next-props]
|
||||
(om/set-state! owner :name (:name next-props))
|
||||
(om/set-state! owner :grubs (:grubs next-props)))
|
||||
(will-receive-props [this next-recipe]
|
||||
(om/set-state! owner :name (:name next-recipe))
|
||||
(om/set-state! owner :grubs (:grubs next-recipe)))
|
||||
|
||||
om/IRenderState
|
||||
(render-state [this {:keys [edit-state name grubs]}]
|
||||
(let [update (om/get-shared owner :recipe-update)
|
||||
add-grubs-ch (om/get-shared owner :recipe-add-grubs)]
|
||||
(let [update (om/get-shared owner :recipe-update)]
|
||||
(html
|
||||
[:div.panel.panel-default.recipe-panel
|
||||
{:on-click
|
||||
|
@ -92,7 +83,7 @@
|
|||
{:type "button"
|
||||
:class (when (= edit-state :editing) "hidden")
|
||||
:ref :add-grubs-btn
|
||||
:on-click #(add-grubs add-grubs-ch grubs)}
|
||||
:on-click #(add-grubs (om/get-shared owner :add-grubs-ch) grubs)}
|
||||
[:span.glyphicon.glyphicon-plus]
|
||||
" Grubs"]]
|
||||
[:div.panel-body.recipe-grubs
|
||||
|
@ -105,7 +96,7 @@
|
|||
:on-change #(om/set-state! owner :grubs (dom/event-val %))}]
|
||||
[:button.btn.btn-danger.pull-left.recipe-remove-btn
|
||||
{:type "button"
|
||||
:on-click #(put! (om/get-shared owner :recipe-remove) (remove-event id))}
|
||||
:on-click #(put! remove-recipe-ch id)}
|
||||
[:span.glyphicon.glyphicon-trash]]
|
||||
[:button.btn.btn-primary.pull-right.recipe-done-btn
|
||||
{:type "button"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
(ns grub.view.recipe-list
|
||||
(:require [om.core :as om :include-macros true]
|
||||
[sablono.core :as html :refer-macros [html]]
|
||||
[cljs.core.async :as a :refer [<! put! chan]]
|
||||
[cljs.core.async :as a :refer [<! chan]]
|
||||
[cljs-uuid.core :as uuid]
|
||||
[grub.view.dom :as dom]
|
||||
[grub.view.grub :as grub-view]
|
||||
|
@ -9,12 +9,14 @@
|
|||
(:require-macros [grub.macros :refer [log logs]]
|
||||
[cljs.core.async.macros :refer [go go-loop]]))
|
||||
|
||||
(defn add-recipe [ch name grubs owner]
|
||||
(defn add-recipe [owner name grubs]
|
||||
(when (and (not (empty? name))
|
||||
(not (empty? grubs)))
|
||||
(om/set-state! owner :new-recipe-name "")
|
||||
(om/set-state! owner :new-recipe-grubs "")
|
||||
(put! ch (recipe/add-event name grubs))))
|
||||
(let [recipes (om/get-props owner)
|
||||
new-recipe (recipe/new-recipe name grubs)]
|
||||
(om/set-state! owner :new-recipe-name "")
|
||||
(om/set-state! owner :new-recipe-grubs "")
|
||||
(om/transact! recipes #(assoc % (:id new-recipe) new-recipe)))))
|
||||
|
||||
(def transitions
|
||||
{:waiting {:click :editing}
|
||||
|
@ -28,7 +30,7 @@
|
|||
[:editing :save :waiting] (let [add-ch (om/get-shared owner :recipe-add)
|
||||
name (om/get-state owner :new-recipe-name)
|
||||
grubs (om/get-state owner :new-recipe-grubs)]
|
||||
(add-recipe add-ch name grubs owner))
|
||||
(add-recipe owner name grubs))
|
||||
nil)
|
||||
(om/set-state! owner :edit-state next)))
|
||||
|
||||
|
@ -36,11 +38,10 @@
|
|||
(reify
|
||||
om/IInitState
|
||||
(init-state [_]
|
||||
(let [publisher (chan)]
|
||||
{:edit-state :waiting
|
||||
:new-recipe-name ""
|
||||
:new-recipe-grubs ""
|
||||
:unmounted false}))
|
||||
{:edit-state :waiting
|
||||
:new-recipe-name ""
|
||||
:new-recipe-grubs ""
|
||||
:unmounted false})
|
||||
|
||||
om/IRenderState
|
||||
(render-state [this {:keys [edit-state new-recipe-name new-recipe-grubs]}]
|
||||
|
@ -67,7 +68,7 @@
|
|||
{:type "button"
|
||||
:ref :save-btn
|
||||
:on-click #(transition-state owner :save)}
|
||||
"Save"]]]))
|
||||
[:span.glyphicon.glyphicon-ok]]]]))
|
||||
|
||||
om/IWillMount
|
||||
(will-mount [_]
|
||||
|
@ -92,12 +93,24 @@
|
|||
|
||||
(defn view [recipes owner]
|
||||
(reify
|
||||
om/IRender
|
||||
(render [this]
|
||||
om/IInitState
|
||||
(init-state [_]
|
||||
{:remove-recipe-ch (chan)})
|
||||
om/IRenderState
|
||||
(render-state [_ {:keys [remove-recipe-ch]}]
|
||||
(html
|
||||
[:div
|
||||
[:h3.recipes-title "Recipes"]
|
||||
(om/build new-recipe-view recipes)
|
||||
[:ul#recipe-list.list-group.recipe-list
|
||||
(for [recipe (vals recipes)]
|
||||
(om/build recipe/view recipe {:key :id}))]]))))
|
||||
(om/build recipe/view
|
||||
recipe
|
||||
{:key :id :opts {:remove-recipe-ch remove-recipe-ch}}))]]))
|
||||
om/IWillMount
|
||||
(will-mount [_]
|
||||
(let [remove-recipe-ch (om/get-state owner :remove-recipe-ch)]
|
||||
(go-loop []
|
||||
(let [removed-id (<! remove-recipe-ch)]
|
||||
(when-not (nil? removed-id)
|
||||
(om/transact! recipes #(dissoc % removed-id)))))))))
|
||||
|
|
Loading…
Reference in a new issue