luciodale / fork

A non-intrusive Clojurescript form management library for Re-frame and Reagent.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Set-submitting does not work for reagent

mitchellandwebb opened this issue · comments

I've defined the form like this (approximately):

(defn my-form []
  [{:keys [values
           handle-change
           handle-submit
           submitting?
           form-id
           ]}]
  (let [name "name"
        email "email"
        message "message"
        ]
    [:form { :on-submit handle-submit
             :id form-id
            }
     
     [:div {:class "ContactPage-NameGroup"}
      [:label {:for name} "Name"]
      [:input {:type "text", :id name, :name name
               :on-change handle-change
               :value (values name)
               }]
      ]
     [:button {:type "submit"
               :disabled submitting?
               }
       "Submit"
      ]
     ])
)

(defn form []
    [f/form { :prevent-default? true
              :clean-on-unmount? true
              :path :contact-form
              :on-submit (fn [{:keys [state path values dirty reset]}]
                          (f/set-submitting state path true))
             }
      my-form
     ])

When I click the submit button, I get an error in the console that says there's no protocol IAssociative defined for reagent's Ratom.

I've looked at the source code fork/reagent.cljs, and it looks like the the error is coming from my call to set-submitting. I'm passing in state, but that state is a Ratom that gets passed to core/set-submitting, which attempts to add a key to the ratom, which obviously doesn't work.

In the re-frame version, it looks like you pass db, which is specific to reframe? If so, how would I get the set-submitting to work with reagent, so I can make the submit button disabled while submitting?

Looked at it further, and I changed my :on-submit function to

              :on-submit (fn [{:keys [state path values dirty reset]}]
                           (swap! state #(assoc-in % [path :submitting?] true))
                          )

This fixed the issue in my code, but I would hazard that a fix still needs to be made in fork.

Hello! I should definitely update the README to clarify the behaviour of set-waiting, set-submitting and set-server-message.

As you already figured out, they do not perform the swap! operation for you. The idea behind it is that all the state changes should be sent together when possible, therefore triggering only one re-render.

To explain this in an example, let's assume that set-submitting can take an atom and perform the swap! operation:

:on-submit (fn [{:keys [state path values dirty reset]}]
                    (f/set-submitting state path true))

If my use case requires me to do something else with the state besides setting submitting, then I would end up with:

:on-submit (fn [{:keys [state path values dirty reset]}]
                   (f/set-submitting state path true)
                   (swap! state update ...))

As you can see, swap! is being called inside set-submitting and by my custom logic, which is not ideal. Contrarily, with the current behaviour of set-submitting you can easily do everything in one swap! like this:

:on-submit (fn [{:keys [state path values dirty reset]}]
             (swap! state #(-> %
                              (f/set-submitting path true)
                              (update :some-key inc))))

Also, note that if you only need to perform the set-submitting operation, you can simply pass the function to the atom like this:

(swap! state f/set-submitting path true)

Hope this explanation helps :)

Yes, please update the documentation, because the Reframe example doesn't seem to know about atoms.

But that helps a lot, thanks!