untangled 2017-06-25

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.

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

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

around line 890 of forms.cljc

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

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.

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

improve the library

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

Ideally would events be in the forms-spec?

forms-spec is data

goes in app state

functions cannot go in there.

Technically, you could add a transaction’s content

to form-spec

but then you’d have to deal with parameters somehow

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

heck, ??? is a legal sym

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

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"

is there a question there?

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

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))))

you can see the transact there 2/3rds down

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

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

The form-field multimethod supports params

but dropdown ignores them

get-custom-on-form-change-mutation

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

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

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

New code would be picking up the onChange.

and just running it in the onChange of the input

along with the built-in form stuff

it is a trivial change/improvement

most of the form fields should have it

but they don’t

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

the code I just posted is the current impl

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

with the new value

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

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

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

forgot about that

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...

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

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.

@cjmurphy Merged and released to clojars 1.0.0-SNAPSHOT

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.

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.

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