Fork me on GitHub
#om
<
2017-05-09
>
vitalije07:05:33

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.

vitalije07:05:12

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.

vitalije07:05:29

What am I missing?

vitalije07:05:14

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.

claudiu08:05:17

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

danielstockton08:05:45

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.

vitalije09:05:28

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?

danielstockton09:05:49

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

vitalije09:05:45

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)

vitalije09:05:39

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

danielstockton09:05:41

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.

danielstockton09:05:34

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

danielstockton09:05:04

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

danielstockton09:05:27

Then [(increment {:id :a})

claudiu09:05:49

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

claudiu09:05:21

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

claudiu10:05:32

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.

danielstockton10:05:16

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

vitalije10:05:32

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

claudiu10:05:43

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

vitalije10:05:06

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

vitalije10:05:19

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.

vitalije10:05:57

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.

vitalije10:05:12

showing and changing data on given path.

vitalije10:05:07

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

danielstockton10:05:33

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

vitalije10:05:05

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

vitalije10:05:35

I mean further clicks had no effect.

claudiu10:05:13

with om/get-computed

vitalije10:05:19

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.

vitalije10:05:36

@claudiu Thanks you have solved it.

claudiu10:05:13

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

claudiu10:05:28

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

vitalije10:05:34

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?

claudiu11:05:06

For rendering, unsing this approach

danielstockton11:05:49

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.

claudiu11:05:50

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.

claudiu11:05:46

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

vitalije11:05:53

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

vitalije14:05:56

Thank you @claudiu it works just fine.

claudiu15:05:54

Youre welcome :)