untangled

NEW CHANNEL: #fulcro
fz 2017-05-30T00:47:43.875896Z

How can I chain mutation functions in a load post-mutation? https://clojurians.slack.com/archives/C06DT2YSY/p1496100336889588

tony.kay 2017-05-30T00:49:05.882058Z

chaining: I don’t recommend that…kinda messy. Rather, write a support function that accepts a state map for all of your state manipulations, then it is easy to chain them:

fz 2017-05-30T16:12:18.947718Z

@tony.kay FYI use case, in case it's helpful for future designs — essentially I want my post mutation to do 'foo and 'bar, but 'bar itself is also a mutation that can be triggered from elsewhere in the UI. For example, after loading data fields on a record, I want to expand a detail view and select a particular tab; selecting a particular tab is a mutation that can be triggered by the user via the UI as well.

tony.kay 2017-05-30T17:42:33.806211Z

was there a question in there? It sounds like my response from 5:49pm yesterday (PST) applies just fine.

fz 2017-05-30T21:32:33.269111Z

It does. No question here, was thinking about it and realized it might be useful in general to share my use case 🙂

tony.kay 2017-05-30T00:49:30.883966Z

(swap! state (fn [s] (-> s  (do-a) (do-b) (do-c))))

tony.kay 2017-05-30T00:50:56.890777Z

and your simple mutations are just (defmutation do-thing [args] (action [{:keys [state]}] (swap! state do-thing)))

tony.kay 2017-05-30T00:53:28.902638Z

but technically, there is no problem with pulling an action out of a call to mutate. It is just a multimethod.

tony.kay 2017-05-30T00:55:48.913918Z

(defn open-menu-impl [state-map id] (assoc-in state-map [:menu/by-id id :open?] true)

(defmutation open-menu [{:keys [id]}]
  (action [{:keys [state]}] (swap! state open-menu-impl id)))

fz 2017-05-30T01:00:13.937849Z

Makes sense — thank you

tony.kay 2017-05-30T01:00:21.938741Z

welcome

mitchelkuijpers 2017-05-30T14:15:16.201454Z

Has anyone extended untangled-ui forms support in a way that you can have a field which has a query? I have a field that needs to load options from a remote place and then show them and then you can create or select an existing. I tried to make a field and now I am creating a subform But then I have the problem that the subforms ident will change based on what the user selects.. Not sure if that is a problem btw.

mitchelkuijpers 2017-05-30T14:18:49.282077Z

btw I think that making this a subform is the wrong solution for what I am trying to do

fz 2017-05-30T16:12:18.947718Z

@tony.kay FYI use case, in case it's helpful for future designs — essentially I want my post mutation to do 'foo and 'bar, but 'bar itself is also a mutation that can be triggered from elsewhere in the UI. For example, after loading data fields on a record, I want to expand a detail view and select a particular tab; selecting a particular tab is a mutation that can be triggered by the user via the UI as well.

tony.kay 2017-05-30T17:38:15.719006Z

@mitchelkuijpers Yeah, it isn’t a subform. What you want is a control that has it’s query, a load that fills in that control, and a callback that can tell you when you’ve interacted (selected). Then you can hook the callback up to fill in the form field (just modify the value in app state).

tony.kay 2017-05-30T17:38:52.730984Z

and probably pass in the current value via computed (since you won’t be querying for the current selection in the control).

tony.kay 2017-05-30T17:39:40.746991Z

So, you have UI control that takes the possible selections (via query), a selected value (via computed), and has a callback to tell you when it is selected. The parent (form) does the transact to update the actual value.

tony.kay 2017-05-30T17:40:25.762407Z

and since forms are just stacked on top of regular state, that just means updating that field’s value. Of course, you’ll want that field to be properly declared (for submission, dirty check, etc.)

tony.kay 2017-05-30T17:40:39.767499Z

but the control details are just orthogonal.

tony.kay 2017-05-30T17:42:33.806211Z

was there a question in there? It sounds like my response from 5:49pm yesterday (PST) applies just fine.

tony.kay 2017-05-30T17:43:19.821824Z

@timovanderkamp just for my info: are you planning on making those extensions to om-css?

timovanderkamp 2017-05-30T17:44:36.848702Z

@tony.kay yes, but first i will continue playing with this version to see if more has to be fixed

tony.kay 2017-05-30T17:44:58.856392Z

great

tony.kay 2017-05-30T17:45:16.862762Z

that’s always a good approach. see where things are broken usually leads to better design

timovanderkamp 2017-05-30T17:58:46.148191Z

:)

mitchelkuijpers 2017-05-30T18:20:53.609099Z

@tony.kay I was a bit scared of just modifying the app state. But I will try this out. Good to know that I am on the right track

mitchelkuijpers 2017-05-30T18:23:06.655026Z

The hardest part is getting the current value since it is an ident and I cannot query the form state (I think)

timovanderkamp 2017-05-30T19:00:50.441505Z

I was also thinking.. wouldnt implementing a $ prefix for preventing localization make the Global protocol unnecessary?

tony.kay 2017-05-30T19:28:49.982391Z

@mitchelkuijpers You have to query the form state (e.g. your field value)

tony.kay 2017-05-30T19:30:16.011224Z

@timovanderkamp Hm. I was thinking that it would mainly be top-level components that would contribute to the global. Something like a Button should not need to, but you might need the nesting selectors.

tony.kay 2017-05-30T19:30:27.014772Z

So, I’d say both are nice to have

mitchelkuijpers 2017-05-30T19:31:03.026766Z

Ah so just query the untangled.ui.forms/form-key

tony.kay 2017-05-30T19:31:10.028790Z

oh, not what I meant 🙂

tony.kay 2017-05-30T19:31:31.035645Z

yes, you do query that, but the current value is just your local current value…you still treat the form-data as opaque

tony.kay 2017-05-30T19:31:37.037382Z

it is the “pristine” copy

mitchelkuijpers 2017-05-30T19:31:39.037990Z

Ah ok

tony.kay 2017-05-30T19:31:50.041583Z

along with field decl config

mitchelkuijpers 2017-05-30T19:31:51.042050Z

So maybe just copy the current value from the ident when it's get selected

tony.kay 2017-05-30T19:32:15.049875Z

um. let me try an example…forgive me if I don’t get the naming right, I don’t have it all in my head:

mitchelkuijpers 2017-05-30T19:32:47.059997Z

No problem, I have been breaking my head a bit to long about this so I might be a bit slow today

tony.kay 2017-05-30T19:35:23.109273Z

(defui SelectorComponent
  ... query for your selector, which will act as UI for form field. This is NOT a form field ...
  ... ident ...
  (render [this] 
    (let [{:keys [current-value onChange] (om/get-computed this)
          {:keys [selections]} (om/props this)]
    ... render your selector, with current-value, and selections. Call onChange when a change happens))

tony.kay 2017-05-30T19:35:42.115282Z

That would be the selector thingy. It is not part of the form…just a UI component with query, ident, and some computed stuff

tony.kay 2017-05-30T19:37:01.140556Z

Then, your form. Let’s say you’re selecting tire-size. At some point you’ll need to load the tire sizes for the selections of the above component, but that is orthogonal to the form…just for the selector thingy

tony.kay 2017-05-30T19:39:23.183669Z

(defui TireForm
   ... declare form fields, including :tire-size ...
   ... query (include :tire-size and other form stuff, ALSO include a join {:tire-selector (om/get-query SlectorComponent)}) >..
   ... ident as usual ...
   (render [this]
      ; let, extracting tire-size and tire-selector
      (ui-selector (om/computed tire-selector {:current-value tire-size}))
      ; other form stuff))

tony.kay 2017-05-30T19:39:57.194274Z

so you see you’re feeding the selector the current value through computed

tony.kay 2017-05-30T19:40:07.197643Z

so the selector can be parallel to your form

tony.kay 2017-05-30T19:40:26.203661Z

You can just mutate the tire-size as you would in any component

tony.kay 2017-05-30T19:41:44.228508Z

Now, you could abstract that all into functions (one that returns the query bit, one that calls the rendering with proper options) and add that in the form-field multi-method.

mitchelkuijpers 2017-05-30T19:42:43.246940Z

So basically just create a component which handles the options and the current value, and then on change updated the correct part of the form-state so I still get the pristine and other goodies

tony.kay 2017-05-30T19:43:10.255108Z

yeah, this is how you’d implement a form field extension that also needs to query for data

tony.kay 2017-05-30T19:43:39.264279Z

:tire-selector isn’t part of the form, per-se, it is just rendering assistance

mitchelkuijpers 2017-05-30T19:44:42.283487Z

Yeah the biggest problem was that I need to add a query, form-spec item and a certain render. But maybe I can just extend the multimethod which I also did for our own text-field component and then just create a function for the needed queries based on the form-spec

mitchelkuijpers 2017-05-30T19:44:57.288316Z

Big + of creating a data structure for the form

mitchelkuijpers 2017-05-30T19:46:08.311045Z

Thank you @tony.kay this helps a lot. I was banging my head against a wall

tony.kay 2017-05-30T19:46:28.317679Z

no problem.

fz 2017-05-30T21:32:33.269111Z

It does. No question here, was thinking about it and realized it might be useful in general to share my use case 🙂

urbank 2017-05-30T22:49:05.252558Z

Can you think of an example when you would use rather vanilla omnext (build some custom framework around it) instead of untangled?