I am creating a page that displays, and then edits, renter info using om-boostrap. (I know Clojure, but am new to CLJS/Om/React/modern web development in general.) The UI and functionality between displaying and editing tenant info is similar -- both can use input fields; editing just needs the fields to be "text" instead of "static" and needs "Submit" and "Cancel" buttons.
The problem I face is that I can't figure out the React/Om way to change a component like that. The view is defined as follows:
(defcomponent view [{:keys [id] :as app} owner]
(render
[_]
(let [tenant (get @tenants id)]
(dom/div
(om/build header/header-view app)
(dom/div {:class "h3"} "View Tenant\t"
(utils/button {:on-click (fn []
(om/update-state! owner
#(assoc app :edit? true))
(om/refresh! owner))}
"Edit"))
(om/build tenant-info {:edit? (:edit? app)
:tenant {:id id
:name "Funny name"
:unit-addr "Funny addr"
:rent "Lots of rent"}})))))
I won't paste the entire tenant-view
function here, but it builds Bootstrap inputs for each tenant data field using om-bootstrap:
. . .
(let [input-type (if edit? "text" "static")]
(i/input {:ref "name-display"
:type input-type
:label "Tenant Name"
:label-classname "col-xs-2"
:wrapper-classname "col-xs-4"
:value (str name)})
. . .)
I've tried multiple approaches. I've posted my most recent, using the button's :on-click
function to modify the app state, setting the edit?
property to true
and prompting a re-render to make the inputs editable.
This doesn't work and I am not finding guidance in the React or Om documentation.
view
function's input fields.)UPDATE: I can get the inputs to be editable when I hard-code the edit?
flag to true
, so making the inputs editable is not the issue: the problem is toggling from static
to text
(and presumably vice versa).
Yes the problem has to do with understanding the difference between the app state and component state. In this case we wish to affect the app state,I don't understand your scenario quite well but I think it would be better to use component local state for this. You can use init-state
or :state
. and you can use om/update-state!
as you wish. However just adding onto the previous answer it would be easier to just use om/update!
to affect the app state in your scenario.
(utils/button {:on-click #(om/update! app [:edit?] true)}
"Edit")
is another option where you can have the vector of keywords go as deep into the map as you like.
This is more terse but might cause a JS console warning because we ignore the event
from on-click
.