0

How can I trigger the onchange event of a controlled input in a Reagent application?

[:input {:on-change (fn [e] ...) :id :my-input}]

Reagent implements React and the input components are Controlled React inputs so as I found out the input eventually doesn't have the on-change function. It has some kind of React property that contains the passed on-change function and the default on-change fn is nil in the input element object.

So therefore this doesn't working:

(let [input (.get-element-by-id js/document "my-input")]
     (.onchange input))

The purpose is that I have input fields and I want to make a field value validator that could be called anytime (e.g. clicking on a submit button). So I put the validator in the on-change function and it works well but now I need to call the on-change function if I want validate the fields when Im clicking on the submit button.

I tried this but nothing happened:

(defn input
  []
  (letfn [(f [] (let [e (js/Event. "change")
                      el (.getElementById js/document "my-input")]
                     (.dispatchEvent el e)))]
     [:<> [:input  {:id :my-input :on-change (fn [_] (println "Changed"))}]
          [:button {:on-click f} "Trigger on-change"]]))
  • It occurs to me that it may be possible to factor the validation out to be a pure function of something nice that you have access to both for live validation and for validation before submit. Then `:on-change` and submit could both call that function. --- firing the event looks like it might be a mess (dependent on the browser, react version, etc...) – Harold May 10 '23 at 23:49
  • I know at first look it seems difficult but I think there is a simple answer somewhere in the Universe. I chose this approach because the input component takes a field ID and a field props parameter and the field props map contains the validator function but the validate! event is a Re-Frame event and it doesnt get the field props map it only knows the field ID. So the Reagent component knows the validator function but the Re-Frame event doesn't and I really don't want to store the props map in a state atom in order to provide it for Re-Frame events. – Bit Handshake May 11 '23 at 01:05
  • Understood - I'm always looking for the functional answer. Here's a related question that might help: https://stackoverflow.com/questions/23892547/what-is-the-best-way-to-trigger-change-or-input-event-in-react-js – Harold May 11 '23 at 01:29
  • I couldn't make it work so I put the code that I've just tried to the question. – Bit Handshake May 11 '23 at 03:17

2 Answers2

1

What you are trying to do is a bad idea, since the browser treats events triggered by the user differently than those triggered by code. So, you might find stuff work on the actual :on-change but not otherwise. Instead, just write a function to do what you want.

(defn stuff-i-want-to-happen [maybe with args] ...)

(defn input []
  [:<> [:input {:on-change (fn [_] (println "Changed") (stuff-i-want-to-happen 1 2 3)}]
       [:button {:on-click #(stuff-i-want-to-happen 4 5 6)} "Trigger on-change"]])

If you need to track additional state, you can just move that to the appropriate place.

Thomas Heller
  • 3,842
  • 1
  • 9
  • 9
0

The purpose is that I have input fields and I want to make a field value validator that could be called anytime (e.g. clicking on a submit button).

Since you are using Reagent, I think what you want is to use form validator hooks. You can rummage around npm but one I would suggest is react hook form

It does require you to learn their concept of "registering" a validation but it will be able to keep up with all of you validation needs (which only grow as real users get involved).

Phil Cooper
  • 5,747
  • 1
  • 25
  • 41