0

As a React/Om newbie I am not sure if this issue is Om-specific.

I want to build a date entry component based on free text entry. It includes an <input> field where they can type, and a <p> displaying the parsed date (if it's valid).

I implemented it as:

(defn parse-date [e owner]
  (let [text (.. e -target -value)]
    (om/set-state! owner :parsed-date text)))

(defn date-entry [app owner]
  (reify
    om/IInitState
    (init-state [_] {:parsed-date ""})
    om/IRenderState
    (render-state [this state]
      (dom/div nil
               (dom/input #js {:type "text" 
                               :ref "date"
                               :id "new-date"
                               :onChange #(parse-date % owner)})
               (dom/p     nil (:parsed-date state))))))

Unfortunately, as soon as I plug this change handler in, it doesn't behave as expected. When I type a digit in the input field, I can see it appear in the input and the <p> next to it, but then it disappears from the input immediately.

I am able to work it around by putting the text on state:

(defn parse-date [e owner]
  (let [text (.. e -target -value)]
    (om/set-state! owner :parsed-date text)
    (om/set-state! owner :text text)))

(defn date-entry [app owner]
  (reify
    om/IInitState
    (init-state [_] {:parsed-date "" :text ""})
    om/IRenderState
    (render-state [this state]
      (dom/div nil
               (dom/input #js {:type "text" 
                               :ref "date" 
                               :id "new-date" 
                               :onChange #(parse-date % owner) 
                               :value (:text state)})
               (dom/p     nil (:parsed-date state))))))

However, I am surprised I had to do it. Is it really necessary? Can someone please explain what's going on here or point me to relevant docs? Why does plugging in a change handler calling set-state! swallow the event?

Konrad Garus
  • 53,145
  • 43
  • 157
  • 230

1 Answers1

1

Yes it's necessary. Every time the state changes, DOM re-renders and clears your input's value. So if you have no :value in your :input's attributes, it will be cleared.

The reason for this is that when React.js starts diffing the real DOM, with the virtual one, it finds that there's some value in the real attribute, while there is none in the virtual DOM, and therefore it clears it, assuming that's what you want. You should always be explicit about what the DOM should look like (eg. your 2nd snippet).

skrat
  • 5,518
  • 3
  • 32
  • 48