0

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.

  1. What is the right way to render the same component differently? (In my case, the view function's input fields.)
  2. What React or Om documentation is relevant?

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).

MonkeyWithDarts
  • 755
  • 1
  • 7
  • 17
  • Can't you do an awful lot in terms of view variation using css? I'm just looking at the `defui TodoItem` at the bottom of the page [here](https://github.com/swannodette/om-next-demo/blob/master/todomvc/src/cljs/todomvc/item.cljs) where DN has class as "completed " and/or "editing" and that comes straight from the state. – Chris Murphy Dec 13 '15 at 17:47
  • I'm assuming the 'submit' and 'cancel' buttons toggle the :edit? attribute back to false to indicate the record is not being edited (and should not be editable fields). The other thing you probably want is to set the 'disabled' attribute on the input fields when not in edit mode - this will ensure people cannot try and edit the field values before they have selected edit. Obviously, when they hit edit, you will need to remove the disabled attribute – Tim X Dec 14 '15 at 03:17
  • Chris, I will look closer at that example to see if it demonstrates what I am looking for. Tim X, yes, that is what I would want -- but as I said, the problem I face is that the input fields are not being set to "text" (allowing editing). The "static" type on the input makes the inputs display as regular text, preventing editing. – MonkeyWithDarts Dec 14 '15 at 21:34

2 Answers2

1

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.

urbanslug
  • 146
  • 1
  • 8
0

I think the problem is you are using om/update-state! which is for transitioning component local state instead of om/transact! which is used for updating the props passed in to your component. So try changing your button component to this:

(utils/button {:on-click (fn []
                             (om/transact! owner #(assoc app :edit true)))}
                             "Edit")
Leeondamiky
  • 161
  • 3