reagent-project / reagent-forms

Bootstrap form components for Reagent
339 stars 78 forks source link

Checkbox doesn't update if initialized ticked #110

Closed hjrnunes closed 6 years ago

hjrnunes commented 7 years ago

If the checkbox is initialized checked, it always remains checked when you click it.

This was introduced in #100 on a fix to #97

The problem occurs only when {:name true}:

This doesn't work:

(defn mycheckbox []
  (let [doc (atom {:name true})]
    (fn []
      [:div
       [:p (str @doc)]
       [bind-fields
        [:input {:field :checkbox :id :name}]
        doc]
       [:button
        {:on-click #(reset! doc nil)} "clear"]])))

But this works:

(defn mycheckbox []
  (let [doc (atom {:name false})]
    (fn []
      [:div
       [:p (str @doc)]
       [bind-fields
        [:input {:field :checkbox :id :name}]
        doc]
       [:button
        {:on-click #(reset! doc nil)} "clear"]])))

@yogthos can you give a bit of clarity on how the ticking/unticking is bound to the atom? I tried looking at radio buttons but couldn't figure it out. When is (bind) called?

yogthos commented 7 years ago

The bind function is called by the set-attrs function that gets called here when an input field is created. This multimethod decides whether something is an input field or not. When the checkbox type field is resolved its initializer is then called here.

hjrnunes commented 7 years ago

Thanks. I didn't express myself accurately.

What I wanted to ask is how does the ticking/unticking relate to the bind method? As far as I can see, both init-fields and bind are only called once when the component is loaded or am I missing something?

yogthos commented 7 years ago

That's correct, the functions are called once when the component is loaded, and the render-element macro returns a widget that's managed by Reagent from that point on.

hjrnunes commented 7 years ago

Ok. So do you know how Reagent ties into the checking behaviour?

Supposedly, you set the checkbox to checked with a "checked" attribute. That's what we're doing.

But then, when I watch in dev tools, ticking/unticking doesn't change the DOM input element.

Essentially, that's problem. Somehow, without setting "checked" in the attrs, things work fine and the on-change callback updates the atom, etc. But because the DOM isn't actually changing (or so it seems), if you initially set "checked", it will always stay there - because init-fields and bind only run once.

Any ideas on how to tackle this?

yogthos commented 7 years ago

Yeah setting the "checked" attribute is what toggles the state of the checkbox. Although it looks like you might have to use defaultChecked for the initial state in React. So, perhaps the field should set :default-checked "checked" instead.

yogthos commented 7 years ago

I just pushed out 0.5.25, should fix the issue with the ticked checkbox/radio button initialization.