Fork me on GitHub
#untangled
<
2017-06-25
>
cjmurphy04:06:05

I have a form with a form-spec that includes a f/dropdown-input. I'm looking for the event that 'the user has selected a different value' - I need to transact! a mutation when this happens. It is not clear to me how to go about hooking into the event.

tony.kay05:06:20

@cjmurphy I don’t think, at the moment, it generates events. The form support is young. There is the on-form-change support.

tony.kay05:06:47

You could easily augment the ::dropdown form-field rendering and add support for a callback

tony.kay05:06:21

around line 890 of forms.cljc

cjmurphy05:06:50

was thinking might have to do something like that but looked a bit tricky so thought I'd ask first.

tony.kay05:06:35

not that tricky…there isn’t much to the forms support internally. It just makes a copy of the original field values. The field rendering just hooks up the change events.

cjmurphy05:06:40

So i'll actually have to make a change to the library, or it should be able to handle it?

tony.kay05:06:49

improve the library

tony.kay05:06:06

I think that is a valid use-case: wanting to add you own additional event handling to change events

cjmurphy05:06:19

Ideally would events be in the forms-spec?

tony.kay05:06:33

forms-spec is data

tony.kay05:06:36

goes in app state

tony.kay05:06:42

functions cannot go in there.

tony.kay05:06:55

Technically, you could add a transaction’s content

tony.kay05:06:59

to form-spec

tony.kay05:06:06

but then you’d have to deal with parameters somehow

tony.kay05:06:23

‘[(do-thing {:value ???})]` is valid data, and we could technically invent a placeholder for the current value

tony.kay05:06:34

heck, ??? is a legal sym

tony.kay05:06:20

but I think it makes more sense as a parameter to the field rendering itself.

cjmurphy05:06:25

I can see in the transaction log: [:user-request/by-id USER-REQUEST-FORM] transacted '[(untangled.ui.forms/select-option {:form-id [:user-request/by-id USER-REQUEST-FORM], :field :request/period, :value ":q2"}) {:root/user-request [:untangled.ui.forms/form-root]}], #uuid "95d35c63-658f-4c24-a9bc-6452dfeda882"

tony.kay05:06:56

is there a question there?

cjmurphy05:06:13

So the custom one. mine, can just come after?

tony.kay05:06:42

Ah, so if you were going to improve the lib, the current imple of rendering of that looks:

(defmethod form-field* ::dropdown [component form field-name & params]
  (let [id        (form-ident form)
        selection (current-value form field-name)
        cls       (or (css-class form field-name) "form-control")
        field     (field-config form field-name)
        optional? (= ::none (:input/default-value field))
        options   (:input/options field)]
    (dom/select #js
        {:name      field-name
         :className cls
         :value     selection
         :onChange  (fn [event]
                      (let [value      (.. event -target -value)
                            field-info {:form-id id
                                        :field   field-name
                                        :value   value}]
                        (om/transact! component
                          `[(select-option ~field-info)
                            ~@(get-on-form-change-mutation form field-name :edit)
                            ~form-root-key])))}
      (when optional?
        (dom/option #js {:value ::none} ""))
      (map (fn [{:keys [option/key option/label]}]
             (dom/option #js {:key key :value key} label))
        options))))

tony.kay05:06:53

you can see the transact there 2/3rds down

cjmurphy05:06:00

I really want a 'post change' event on the field.

tony.kay05:06:47

right…so now you’re saying (form-field this form :dropdown), right?

tony.kay05:06:07

The form-field multimethod supports params

tony.kay05:06:13

but dropdown ignores them

cjmurphy05:06:32

get-custom-on-form-change-mutation

tony.kay05:06:34

so you could say (form-field this form :dropdown :onChange (fn [new-val] ...))

tony.kay05:06:51

and add that to the implementation of dropdown’s render in the lib

tony.kay05:06:09

OR copy the dropdown rendering code, and add it to your own type of field…but that would be kinda silly

cjmurphy05:06:24

New code would be picking up the onChange.

tony.kay05:06:35

and just running it in the onChange of the input

tony.kay05:06:41

along with the built-in form stuff

tony.kay05:06:48

it is a trivial change/improvement

tony.kay05:06:59

most of the form fields should have it

tony.kay05:06:03

but they don’t

cjmurphy05:06:18

okay - if its trivial I'll be able to do it 😉

tony.kay05:06:34

the code I just posted is the current impl

tony.kay05:06:53

you can see params already there. Change it to {:keys [onChange]} and then run the onChange in the input

tony.kay05:06:01

with the new value

tony.kay05:06:17

I think the new value…does that seem right? Or should it be the event?

tony.kay05:06:35

could also be both, for convenience, but that is kinda heavy handed

tony.kay05:06:08

actually, I think you need to pass the value (optionally the event), because form fields support transform functions

tony.kay05:06:13

forgot about that

cjmurphy05:06:17

Not sure, I'll get to this later today. Thanks - this forms stuff will become very good very soon. I'm forgetting CSS for the moment, next week...

tony.kay05:06:50

yeah, the forms stuff is young, but it already shows the huge promise

tony.kay05:06:55

just needs these little details, which are better written as we hit some use cases. I have not had the chance to use it much yet.

tony.kay13:06:26

@cjmurphy Merged and released to clojars 1.0.0-SNAPSHOT

tony.kay13:06:24

on dropdowns: If you set a default then it won’t show a “nothing” option. If you want it to show something like required, then just add an entry for “required” that your form validation won’t accept as a value.

tony.kay13:06:29

You have to use form, not field, validation for that (since dropdowns are technically always valid because they are pegged to values you’ve provided)…so either write something on your submit that prevents commit, or use the on-form-change support.

cjmurphy15:06:58

Setting the :input/default-value on my dropdowns got rid of their "nothing" (`:untangled.ui.forms/none`) options perfectly simple_smile