om

Please ask the channel first, not @dnolen directly!
vitalije 2017-05-09T07:34:33.209125Z

Hello to everyone on this channel. I was reading http://read.klipse.tech/om-next-interactive-tutorial/ section "Components With Queries & Mutations". There is example of Counter component that consists of a label showing the state of counter and a button to increase counter. I wish to see reusing this Counter component and so I made a some changes.

vitalije 2017-05-09T07:38:12.247565Z

At first render everything is ok. Labels show numbers as expected. But when clicked first two buttons there is no effect. When clicked last button it's counter value disappears.

vitalije 2017-05-09T07:38:29.250590Z

What am I missing?

vitalije 2017-05-09T07:48:14.360825Z

I found that click on any button increments count at the root of app-state-5. So something is missing in mutate function or in om/transact! call.

claudiu 2017-05-09T08:25:17.816881Z

really curius about this one also. Appears like when you do the mutation afterwords the state is {:a (om/get-query Counter)} .

2017-05-09T08:33:45.929367Z

Your mutation is not updating :count under :a or :b so you would not expect the first two buttons to have any effect. transact! only triggers a re-render on the component it's called on, unless you pass in extra reads.

vitalije 2017-05-09T09:21:28.573181Z

So every instance of Counter should have it's own mutate method? Is there any way to reuse Counter component to increase count fields in other parts of app state?

2017-05-09T09:22:49.591599Z

You could have a single method that accepts a path in the app-state to update as a parameter e.g. [(increment {:path [:a]})].

vitalije 2017-05-09T09:27:45.656237Z

Can you @danielstockton, please, suggest how the above code should be changed so that every button increases it's own field (the same own it uses for reading)

vitalije 2017-05-09T09:30:39.696452Z

Or how component can find it's own path to send in transact! call as parameter?

2017-05-09T09:32:41.723684Z

It's not that straightforward for the component to find it's own path, afaik. I would just restructure the app-state, giving each component an id, and then updating a count in a map under that id.

2017-05-09T09:33:34.735715Z

The id can be the key you use to join the query (`:a` or :b), in effect this is what you already have.

2017-05-09T09:34:04.742524Z

(defn mutate [{:keys [state] :as env} key {:keys [id]}]
  (if (= 'increment key)
    {:value {:keys [:count]}
     :action #(swap! state update-in [id :count] inc)}
    {:value :not-found}))

2017-05-09T09:34:27.747418Z

Then [(increment {:id :a})

claudiu 2017-05-09T09:57:49.057629Z

@vitalije Iโ€™m new to clojurescript & om-next so might be wrong about this.

claudiu 2017-05-09T09:58:21.064485Z

Using om/indent seems to be the way to reuse components so that om-next knows where the data is coming from https://github.com/omcljs/om/wiki/Components%2C-Identity-%26-Normalization

claudiu 2017-05-09T10:03:32.135546Z

the only way I managed to make youโ€™re example work is by calling the reconciler instead of the component. But that just re-renders the entire app and behaves like initial render.

claudiu 2017-05-09T10:04:05.142740Z

should not do this, but just for exeprimenting: https://gist.github.com/claudiuapetrei/b8b8d3d33544aa42d618485c6484d978

2017-05-09T10:06:16.170724Z

[(increment) :a] should also work, saying "re-read queries of components that care about :a"

vitalije 2017-05-09T10:11:32.235191Z

@claudiu I have tried your gist solution, but it still doesn't increase correct fields.

claudiu 2017-05-09T10:14:43.272885Z

works for me. I modified the app-state and the read-function.

vitalije 2017-05-09T10:28:06.426396Z

@claudiu Thanks. You have also changed id of the root DOM element so when I applied your code it didn't change the correct part of the page and I couldn't see the effect of your code.

vitalije 2017-05-09T10:29:19.440583Z

However, it didn't solve my initial problem. I want component Counter to be usable for any count field in app-state not only on top-level fields.

claudiu 2017-05-09T10:31:31.466104Z

Yep.

vitalije 2017-05-09T10:31:57.471148Z

I don't think that Counter component is too much usable but I just want to learn basics of creating self contained universally applicable components that could be passed query and it would act on that particular path.

vitalije 2017-05-09T10:32:12.474102Z

showing and changing data on given path.

vitalije 2017-05-09T10:33:07.484234Z

You have mention om/Indent, I will read it again.

2017-05-09T10:35:33.512238Z

@vitalije You can also pass through computed props (functions) to be called on particular actions. This way you can have a counter component accept an increment function without actually specifying the mutation to call inside the component.

vitalije 2017-05-09T10:39:05.551534Z

@danielstockton I tried your mutate method and I have got it working once, but after first increment it stopped working.

vitalije 2017-05-09T10:39:35.557062Z

I mean further clicks had no effect.

claudiu 2017-05-09T10:53:13.706061Z

with om/get-computed

vitalije 2017-05-09T10:53:19.707068Z

I have found that when I add path to the Counter components and in click handler pass that path to the 'increment function click on the button increases correctly path but than after re-rendering Counter it looses path information.

vitalije 2017-05-09T10:55:36.732717Z

@claudiu Thanks you have solved it.

claudiu 2017-05-09T10:57:13.751002Z

think the downside to using om/computed in over ident is that the mutation is in the context of the CounterGroup. Because of this om-next will read all the keys from CounterGroup (there was no need to specify fallow on read keys on transact).

claudiu 2017-05-09T10:58:28.764838Z

will try to see if I can get it working with transact inside of the counter component and using om/ident ๐Ÿ™‚

vitalije 2017-05-09T10:58:34.765744Z

But it is not as I hoped to find. ๐Ÿ˜ž It means that user of Component must provide all the functionality. What good will be the Component then?

claudiu 2017-05-09T11:02:06.807687Z

For rendering, unsing this approach

2017-05-09T11:02:49.815962Z

It makes the component more flexible to different app-state stores and schemas. There is nothing stopping you from hard-coding it in the component but it makes it less reusable imo.

claudiu 2017-05-09T11:04:50.838139Z

like written now without ident, only the parent knows where the data is in the appstate ๐Ÿ™‚ so the child canโ€™t really update the state.

claudiu 2017-05-09T11:18:46.990794Z

Again :) might be wrong. Still kinda new. Will also try to see how it goes with ident :)

vitalije 2017-05-09T11:23:53.045413Z

I must leave now. Thank you all. If anyone make it using om/Indent I would greatly appreciate it.

claudiu 2017-05-09T14:42:56.542235Z

@vitalije Works without ident take a look https://gist.github.com/claudiuapetrei/5baa8859fc1f6e7837d5e4aed5e8ca50

vitalije 2017-05-09T14:54:56.839144Z

Thank you @claudiu it works just fine.

claudiu 2017-05-09T15:24:54.592216Z

Youre welcome :)