Fork me on GitHub
#om
<
2015-12-04
>
simonb00:12:14

I needed a unique react key property on a list of child elements. I used a uuid. This sent Om Next into an infinite read/render loop. Is this a bug in Om? That is, can't use uuid as the react key? Or a case of using uuid as a solution increases problem count by one.

noonian01:12:37

do you mean you generated a new uuid on each render?

noonian01:12:49

I think its just react then, and not om, since react uses the uuid’s to know which components have which state when they are reordered. So by generating new ones each render react probably kept re-rendering and the lifecycle things kicked off om’s stuff

simonb01:12:17

@noonian: yes. That was the source of my loop yesterday. Thanks.

noonian01:12:40

np, I’m glad you figured it out

clojuregeek03:12:25

I'm using http://om-bootstrap.herokuapp.com/components .. the modal .. works on the example pops up and closes ... i copy the same to my clojurescript file, it shows the button but doesn't open a modal ... no errors in console or repl ... i'm at a loss at what to do next 😕

Ian Chow05:12:10

@clojuregeek: view the source and styles of the example page and note the difference with yours. think you have to add a css class to your component for it to work.

clojuregeek05:12:10

@ianchow I tried but I will look more closely, thanks

hmadelaine08:12:33

@artemyarulin: thanks for the link, very interesting

thosmos13:12:37

@jgdavey, I think another way to do it is [({:post [:post/title :post/body]} {:post/id 123})] see https://clojurians.slack.com/files/anmonteiro/F0CKAH6TS/screen_shot_2015-10-06_at_18.46.05.png

r0man14:12:25

@dnolen: I read somewhere that "queries must compose to the root". Does this mean that all ui components that I want to use eventually must be reachable from the root? Can I change the root query dynamically later, for example from a module that contains a component I loaded on demand after the first render?

dnolen14:12:04

@r0man: there’s many ways to solve this problem

dnolen14:12:13

you can declare everything and defer

dnolen14:12:21

or you can use om.next/subquery

dnolen14:12:55

people have other ideas as well, but I’ll let them speak for themselves

r0man14:12:50

@dnolen: ok, I'll take a look into subquery. wasn't aware of that ..

dnolen15:12:29

@r0man: this also is what Union Queries are for

dnolen15:12:47

most UIs you know what you’re going to show

dnolen15:12:02

you have some set of views you’ll present

dnolen15:12:11

and the user gets to dynamically choose them

dnolen15:12:19

Union Queries solve this problem

dnolen15:12:47

it also solves the problem of dashboards where you have N different dashboard item types

r0man15:12:05

@dnolen: what I'm trying to do is having a router that loads for each route a module compiled in advanced mode and uses a component from the module to render a page. I can't require and reference a component from those modules in the root component (except via :export), because otherwise the resulting module is empty because the component has been moved to cljs-base. I change the root query dynamically after I loaded the module, but now I think I'm running into problems with normalization. Does this even make sense? simple_smile

dnolen15:12:33

Not really

dnolen15:12:42

Conflating too many things

dnolen15:12:32

you're talking about modules not sure if you actually mean advanced code splitting or something else

dnolen15:12:43

Also nothing prevent queries from being stored in atoms or something and when modules load you extend them

dnolen15:12:49

It's just data after all

r0man15:12:01

@dnolen: yes, I mean modules with advanced code splitting. I load those modules on demand and they contain components with queries and idents. I think my problem is that after mounting the root component the initial state has been normalized with only the ident information reachable from the root. I think I have to normalize again after loading a module and after I changed the root query.

dnolen15:12:25

what you're saying doesn’t really make any sense

dnolen15:12:46

sounds like struggling with 3 completely different problems all at once

dnolen15:12:51

which is unlikely to be productive

dnolen15:12:17

“normalize again” with the information I have thus far just sounds like the wrong conclusion

r0man15:12:43

ok, investigating some alternatives ...

dnolen15:12:15

You may be saying ... I have all the data but not all the queries so I can't normalize everything at the beginning

dnolen15:12:14

But then nothing is preventing you from normalizing the state when you load the new stuff. The reconciler atom is reachable.

tomc16:12:37

Having some trouble setting up url routing. My root view queries for the current :session/route and handles rendering the right component for the result of that query. Now I'm trying to add the query for that component (say, HomePage), but if "all queries must compose to root", then the root view must also know the query for HomePage, and incorporate that into its query. I've tried using a special :ui/root method of my parser's :read multimethod, but I'm unsure of 1) how to directly call read for the child component's query and 2) whether that's even the right approach. Anyone have any ideas or examples I can look at?

scttnlsn16:12:19

@tomc I’m wondering a similar thing. I have a React Native application where the root component renders a screen based on the dynamic value of :screen in the app state. Not sure about how best to compose the query of the screen component with the query of the root component. I’d also love to see some examples.

tomc16:12:11

@scttnlsn: I'll let you know if I come up with anything.

scttnlsn16:12:27

@tomc: Great, thanks

dnolen16:12:28

@tomc: you should review the entire backlog of earlier of what I was telling @r0man

dnolen16:12:37

any or all of the ideas could apply

dnolen16:12:03

you should then try to implement what I said outside of your application

dnolen16:12:07

what you want is trivial to write

tomc16:12:46

@dnolen: are you referring to the discussion you two had this morning? I wasn't sure what you meant by "declare everything and defer"

dnolen16:12:02

just read through it

dnolen16:12:04

think about it

dnolen16:12:09

and try some things

dnolen16:12:18

whatever you come up with it shouldn’t be more than 50 lines of code

dnolen16:12:43

and you have a satisfactory answer for your particular problem write about it

dnolen16:12:37

@tomc I would start with what I said about union queries & subquery

dnolen16:12:08

it’s possible that union query is all that you actually need

dnolen16:12:13

and you could even put the route as data into the application state

dnolen16:12:25

and feed it in so that subcomponents know which part of the union query to load

tomc16:12:56

@dnolen: thanks for the advice. Are there docs on subquery aside from the docstring?

scttnlsn16:12:14

Perhaps my understanding of union queries is wrong but couldn’t using union queries for this use case potentially over-fetch a bunch of data not relevant to the current screen/route?

dnolen16:12:03

you are misinterpreting how they are meant to work

dnolen16:12:12

it’s completely up to you what they mean and what they fetch

dnolen16:12:17

same as everything else in query

dnolen16:12:37

as I’ve said many times Om Next doesn’t do anything at all

dnolen16:12:50

you tell it what to do

scttnlsn16:12:03

Haha, OK. I’ll need to play around with it more

dnolen16:12:37

people keep asking about this so I might just do it

dnolen16:12:43

I don’t really care about the routing problem at all

dnolen16:12:53

but obviously a lot people want some kind of standard answer

scttnlsn17:12:10

@tomc Thanks. That looks like a good example

tony.kay17:12:02

Is anyone using db->tree on unions? I'm trying to figure out if I have a misunderstanding or I've found a bug

thosmos17:12:29

@tomc @scttnlsn I posted a mod of jdubie's router that handles browser history, urls, click capture, and modifying the query for each route. https://github.com/thos37/om-next-router-example

tony.kay17:12:51

@dnolen: I think this is a bug in db->tree: Reading unions in default db format

tony.kay17:12:01

line 1130 on master

tony.kay17:12:07

should be second instead of first

tony.kay17:12:12

at the end of the line

dnolen17:12:35

that’s not a bug

dnolen17:12:47

not saying there isn’t a bug

dnolen17:12:49

just that’s not it

tony.kay17:12:50

yeah, I'm backwards on my ident creation

tomc17:12:30

@thosmos: thanks! I'll check it out.

tony.kay17:12:28

@dnolen: Yeah, that fixed it...I had the elements of my idents backwards because of the way I was thinking about this problem.

tony.kay17:12:36

works perfectly now

jdubie17:12:16

@thosmos: that looks a lot nicer / more how om is supposed to work. i think i’ll put a pointer in my readme to your fork. to clarify your event flow is like this, right?

item clicked -> `change-route` updates browser state -> `nav-handler` update `Root` query and state
this is clean because clicking on a menu item is the same code path as browser navigation

thosmos18:12:06

@jdubie actually I think in that example, item clicked -> pushy updates browser state -> nav-handler ... change-route isn't used because pushy captured the link click. That function would be called if the callback that was passed through om/computed had been used via the link's onclick event. I left it in there to easily compare pushy click capture with the explicit onclick handler.

thosmos18:12:33

Maybe some more comments would help clarify. Also feel free to merge it into yours if you like it.

tony.kay18:12:57

@dnolen: Are unions supposed to work on singleton joins? I'm playing with them in my tutorial query runner, and if I refer to a collection of hetero items it works, but if I drop to a single ident then it fails.

tony.kay18:12:03

same problem if I join on an ident {[:screen-type 0] ...union...}

dnolen18:12:29

@tony.kay: it should work yes

tony.kay18:12:36

k. I'll debug and fix

tony.kay18:12:20

@dnolen: Do you intend join? to return true for unions?

dnolen18:12:08

yes it should since that’s really the only thing they can be

tony.kay18:12:44

To be clear, I asking: (is (join? {:a [:x] :b [:y] :c [:z]})) not (is (join? {:jk {:a [:x] :b [:y] :c [:z]}}))

tony.kay18:12:56

both are passing tests

dnolen18:12:35

the grammar is definitive

dnolen18:12:43

the former is not allowed

dnolen18:12:52

if the grammar is unclear about this should be fixed

dnolen18:12:44

@tony.kay: reading through your process roots patch btw, hoping to apply shortly

tony.kay18:12:37

I understand it is not allowed by the grammar. but a join on a join is, and join? mis-detects that case when looking at it.

tony.kay18:12:48

I think that is what is going on, at least

tony.kay18:12:54

got 3 things in the air at the moment

tony.kay18:12:03

Let me know if you need any info on process roots. We're using it and so far it is doing exactly what we expect. One thing I thought should be added, but have not had time to: If you try to promote two elements that have parameters to the root then merge joins should throw an error.

dnolen18:12:10

ah sorry I didn’t realize you were asking a implementation detail question

tony.kay18:12:12

since there is no way to merge parameters

dnolen18:12:52

you could easily just change the predicate

dnolen18:12:00

join-or-union-frag?

dnolen18:12:23

it really doesn’t matter, it’s nothing anyone will know about

tony.kay18:12:47

I was thinking of changing join? (and (not (union? q)) ...)

tony.kay18:12:11

but that feels dangerous...not open-closed

tony.kay18:12:24

I'll do as you suggest and not touch join?

dnolen19:12:52

Don't touch it

dnolen19:12:08

internal refactoring stuff is not something I’m much interested in until we get everything right first

tony.kay19:12:24

turns out the bug is using next (or possibly the group-by...still working on it), which is calling seq on the joins map and turning it into a list of kv pairs (in the recur of the join processing loop)

tony.kay19:12:19

might be something I introduced via the graph loop code

jdubie19:12:28

just updated https://github.com/jdubie/om-next-router-example thanks to @thosmos. check it out and let me know what you think. improvements: - get rid of hacky top level union query and use om/set-query! - bi-directional route syncing (om state <-> browser url). this keeps parsing pure (only dealing with data) and prevents having to use browser history and other browser apis there. this allows you to change the route by clicking on urls and back button as well as in an om/transact! call - using pushy to manage browser history api

tony.kay19:12:20

@dnolen: fixed. PR in your queue

tony.kay19:12:57

you may want to combine the logic...it reads clearly, but is a bit repetitive

tony.kay19:12:32

eh...hold on that. Let me add some tests. I found another case that fails

dnolen19:12:28

@tony.kay: you might want to rebase, I merged process-roots and made a few cosmetic changes

tony.kay19:12:58

k. will do. I don't have the general sol'n yet either.

tony.kay19:12:33

I need to switch tasks at work...I can point you at the exact problem if you want to look at db->tree; otherwise I can work on it later

thosmos19:12:49

@jdubie: looks pretty good. my main problem with this way of doing it is the multiple re-renders for each transition (4 renders and 2 set-params! for the menu links) There must be abetter way.

noonian19:12:38

I’ve gotten routing working with pushy by having my nav-handler, in the router-example parlance, initiate a transaction with a mutation i.e. [(app/set-page! ~match) :page]

dnolen19:12:39

@tony.kay: sure where are you looking?

tony.kay19:12:40

@dnolen: on db->tree basically during the processing of the join on a singleton bit of data: the union itself ends up as the selector, and that gets passed back recusively to db->tree as the query. So, at entry to db->tree the query is a union, which is not allowed as a top-level query, and thus it gets interpreted as a join. Not sure if we need to change the top-level if, or do sub-processing in the join loop.

tony.kay19:12:12

my PR has it swapping the selector for the specific one (out of the union)...but that only works for joins on an explicit ident

tony.kay19:12:58

not when it is walking from a key in state across an ident

noonian19:12:51

You also have to make a decision about whether to use onClick functions for your links/buttons or just use the href from bidi/path-for and let the history event initiate the transaction.

thosmos20:12:11

@noonian: your mutation seems like the equivalent of the nav-handler's (om/transact! this [(route/update {:new-route ~route}) :route])))` Also, this nav-handler is the history event. When I remove the set-params stuff, the menu and url updates, but the page content doesn't get pulled. The question then is where and how to include the new page's query if not in set-params?

noonian20:12:55

Ah, yeah when I said that I didn’t realize the router example had moved away from the way it was doing it with a join

noonian20:12:08

I’m using a join so I always know the full query statically

noonian20:12:54

And just re-read the pages data after the transaction and in the read impl make sure to only resolve the data for the current page. I keep a link in the app state to the current page and use that for dispatching.

anmonteiro20:12:55

@dnolen: any reason why I'm not getting query passed in the env map when I try out the new update-query! ?

anmonteiro20:12:15

still haven't isolated the problem

dnolen20:12:04

@anmonteiro: not that I can see

anmonteiro20:12:42

alright, I'll dig into it and report back

anmonteiro20:12:48

most probable is I'm doing something wrong

jethroksy20:12:51

@tony.kay: are the answers to D_Queries_Exercises available anywhere?

tony.kay20:12:36

got a lot going on...I added a bunch of new text to many places last night...was just working on unions and discovered an Om bug, so switched to that

tony.kay20:12:50

plus I have a job simple_smile so doing that at the moment

jethroksy20:12:38

that's alright haha, I think the prenormalization threw me off a little

jethroksy20:12:14

can't seem to get it to render correctly, but that's okay, take your time!

anmonteiro20:12:06

@dnolen: so when reading a single keyword it doesn't make sense to pass in a query, is this correct?

anmonteiro20:12:24

e.g. if my query is [{:foo [:join]} :another/foo], when reading :another/foo the env won't have :query. In my point of view it is not needed (and I was doing something wrong) but is it intended?

dnolen20:12:40

intended for it to not have :query yes

anmonteiro20:12:03

makes total sense, thanks. especially if I think back to when it was called selector. sorry for the dumb question

noonian20:12:36

Ok guys, I have an app I’m working on that is super unfinished (basically does nothing), but the client side routing stuff may be interesting to some people and it also has a server remote that I will eventually hook up to an sql db. No promises about when I’ll get around to finishing or documenting as I’ve been sick all this week but I thought I’d mention it since it pertains to some of the routing questions people are having.

noonian20:12:19

Also doesn’t actually change the page yet heh, but should have that soon. I just added the routing since people were talking about it and I’m using the old style that the routing example used, with a join query.

leppert21:12:17

I was reading over the Om Next "Queries with Unions” example (https://github.com/omcljs/om/wiki/Queries-With-Unions) and wondering the best way to sort vectors of idents stored in the app-state. For instance, how would you maintain order of :dashboard/items based on the :favorites count of each item? Is it a matter of doing a read within mutate ‘dashboard/favorite (https://github.com/omcljs/om/blob/b9e1b7a140448fee41d130c655f9a3ae1a340c79/src/devcards/om/devcards/tutorials.cljs#L296) to get the built out :dashboard/items list, running a (sort-by :favorites) and then swap!ing that back to the atom? If I sound confused, it’s because I’m a complete Clojure newbie.

thosmos22:12:36

@noonian: Thanks for sharing. There're some interesting ideas in there.

noonian22:12:11

@thosmos: np, thanks for taking the time to check it out!

noonian22:12:40

@leppert: I think you would need to re-sort the dashboard items inside your swap! function for dashboard/favorite. You could get the list of refs, map om/db->tree over them using the query for Dashboard, sort them, and them map over them again to turn them back into idents and stick the result into the :dashboard/items key of state.

leppert22:12:28

@noonian: thanks, that’s helpful context. It seems a little strange to think of going through a component to get the query, though looking at the Om Next docs that seems to be the primary route. In trying to sort like this, am I perhaps abusing the system?

leppert22:12:00

@noonian: strange in this context, I mean. Generally speaking the query convention makes a lot of sense to me.

noonian22:12:22

@leppert: now that I think of it, you don’t need the query at all (since :favorites is not in a nested piece of data and so wouldn’t have to follow more than the first link). You could do something like this:

noonian22:12:28

(let [st @state
      refs (:dashboard/items st)
      items (map #(get-in st %) refs)
      sorted (into [] (sort-by :favorites items))]
  {:action #(swap! state assoc :dashboard/items sorted)})

noonian22:12:50

I left out the logic to actually increment the favorite of the the one you are favoriting since it would add more code

noonian22:12:02

and all that logic should probably go inside the function passed to swap! to be honest.

leppert22:12:51

@noonian: thanks, that makes sense. I assumed if I circumvented the parser I’d somehow make my data access more brittle, but I suppose since I’m writing the read functions anyhow (no magic there) it’s no more brittle than any other app-state access?

noonian22:12:20

Right, you write the reads and the mutations and Om won’t make any assumptions. The structure that Om uses for normalization is kind of your contract, and it only applies for data that is requested by your UI hehe.

leppert22:12:20

@noonian: Very helpful. Thank you!

noonian22:12:41

@leppert: I’m glad I could help!

anmonteiro22:12:10

@dnolen: what should next-state in componentWillUpdate contain when there is no state change?

anmonteiro22:12:22

(e.g. only prop change)

dnolen22:12:07

the old state

dnolen22:12:20

by which I mean whatever the current state is

anmonteiro22:12:25

it's getting undefined at the moment

dnolen22:12:42

which is what it should be if you never created state

dnolen22:12:54

then yeah that’s a bug

anmonteiro22:12:28

I'm happy to submit a patch, just need some info

anmonteiro22:12:28

should we fallback to omcljs$state if no omcljs$pendingState is there?

anmonteiro22:12:17

alright, submitting issue and working on a patch

tony.kay23:12:45

@dnolen: I'm available again...you working on db->tree, or should I continue?

dnolen23:12:59

@tony.kay: didn’t get a chance to get to it no

tony.kay23:12:19

ok, i'll look atit

tony.kay23:12:33

@dnolen: done, with tests

tony.kay23:12:55

any chance we can get an alpha bump?

dnolen23:12:59

sure thing

tony.kay23:12:16

thanks...tutorial coming along nicely, and these bug fixes are needed for parts of it to work simple_smile