Closed afhammad closed 6 years ago
The library uses postwalk
to go through each element in the template and create a Reagent component out of it. Specifically, it looks for vectors that contain a map with the :field
key and creates appropriate widgets based on the type of the field. All other nodes in the structure are let unchanged.
This is the reason the helper functions need to be evaluated. If you have a function in the template then it will simply be left as is.
Thanks @yogthos.
I'm not sure I understand the helper functions yet, since their output (a vector of dom elements) is what is passed in and not an unevaluated function. i.e how is:
(row "first name" [:input {:field :text :id :first-name}])
different from
[:div
[:label "first name"]
[:input {:field :text :id :first-name}]]
The reason i ask is because I'm having trouble toggling css classes reactively based on a ratom so i'm trying to understand how/when changes are re-rendered.
Assuming this is my template:
(defn template [state]
[:div {:class (str "ui form" (when (:errors @state) " error"))}
[:div {:class (when (get-in @state [:errors :slug]) " error")}
[:label "Slug"]
[:input {:field :text
:id :slug
:placeholder "slug"}]]
and parent
(defn render []
(let [state (r/atom {})]
[:div
[bind-fields
(template state)
state]])
The above dynamic adding of "error" class doesn't work, even though adding console logs there show that the new values are reaching there.
Defining a ratom inside the template function like so seems to do the trick (maybe the readme could do with an example of this?):
(defn template []
(let [errors (r/atom {})]
(fn []
[:div {:class (str "ui form" (when-not (empty? @errors) " error"))}
[:div {:class (when (:slug @errors) " error")}
[:label "Slug"]
[:input {:field :text
:id :slug
:placeholder "slug"}]])))
Obviously there's more to the template including a validation check that resets the errors atom.
Actually that breaks the form binding...
Unfortunately, when you update the atom externally the changes aren't guaranteed to be reflected. The way to add events would be by providing event handler functions as described here.
Wouldn't that require me to run my validation every time anything changes on the form as opposed to only when the submit button is clicked? Not really ideal. How do others handle this scenario?
One approach for validation would be to do it externally and rerun bind-fields after validation. That way the form would get reinitialized with the latest data.
The documentation states: