-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Computing values with re-frame #154
Comments
You can handle computed values via re-frame events, e.g: (ns example.core
(:require
[reagent.core :as r]
[re-frame.core :as re-frame]
[reagent-forms.core :refer [bind-fields]]))
(re-frame/reg-event-db
:init
(fn [_ _]
{:doc {}}))
(re-frame/reg-sub
:doc
(fn [db _]
(:doc db)))
(re-frame/reg-sub
:value
:<- [:doc]
(fn [doc [_ path]]
(get-in doc path)))
(defmulti rule (fn [_ path _] path))
(defn bmi [{:keys [weight height] :as doc}]
(assoc doc :bmi (/ weight (* height height))))
(defmethod rule [:height] [doc path value]
(bmi doc))
(defmethod rule [:weight] [doc path value]
(bmi doc))
(defmethod rule :default [doc path value]
doc)
(re-frame/reg-event-db
:set-value
(fn [{:keys [doc] :as db} [_ path value]]
(-> db
(assoc-in (into [:doc] path) value)
(update :doc rule path value))))
(def events
{:get (fn [path] @(re-frame/subscribe [:value path]))
:save! (fn [path value] (re-frame/dispatch [:set-value path value]))
:doc (fn [] @(re-frame/subscribe [:doc]))})
(defn row [label input]
[:div
[:div [:label label]]
[:div input]])
(def form-template
[:div
[:h3 "BMI Calculator"]
(row "Height" [:input {:field :numeric :id :height}])
(row "Weight" [:input {:field :numeric :id :weight}])
(row "BMI" [:label {:field :label :id :bmi}])])
(defn home-page []
[:div [:h2 "Welcome to Reagent"]
[bind-fields form-template events]]) |
@yogthos Thanks this is super helpful! It might benefit others to have your re-frame documentation in the readme reflect this. The only issue I have w/ this implementation is it assumes the only computed value is the BMI, and I may have several forms with varying computed values. Is there a recommended way to refactor and abstract this such that you can pass in a variable (re-frame/reg-event-db
:set-value
(fn [{:keys [doc] :as db} [_ path value rule]]
(-> db
(assoc-in (into [:doc] path) value)
(when rule
(update :doc rule path value))))) |
Note that the is actually a multimethod that's keyed on the path with the default behavior of doing nothing. So, the pattern I would suggest would be to create rule defmethods for the paths that should trigger business rules to recalculate values. |
With the re-framing example, everything is handled through the
events
function:This works fine for initializing and updating values but what if we wanted to calculate the value of a non-editable field (similar to the BMI example). I have a field that comes from the backend that is non-editable and I want to show the calculation of that field to the user before sending it back over. Is there a way to update a specific field in the
doc
outside of the theevents
function setup?The text was updated successfully, but these errors were encountered: