Fork me on GitHub
#om
<
2015-12-07
>
noonian02:12:41

@dnolen: the parser impl cljc file needs a jvm exception case on this line: https://github.com/omcljs/om/blob/master/src/main/om/next/impl/parser.cljc#L87 This prevents one from requiring om.next.server currently with master.

johanatan05:12:56

Is there a way to force an entire page refresh/redraw on demand (e.g., on [debounced] resize event])?

johanatan05:12:16

I'm rendering a table and there are two unwelcome artifacts on resize (which currently merely incs a counter in app-state to force a render): a) if the vertical size is diminished, then the table remains its previously max height even though I'm rendering a [correct] fewer amount of rows in my render and b) if the vertical size is increased, then the newly added row(s) fall outside the existing 'tbody' presumably because React is trying to be smart/efficient and re-use what existing stuff it can. [This causes React to complain about the orphaned rows in the JS console].

noonian06:12:29

I think calling om/add-root! with the same arguments you used to mount the app originally will force a render. I have figwheel remount the app on reload so that I see any UI changes immediately.

johanatan06:12:51

Yep, that did it! Thx!

anmonteiro11:12:12

@johanatan: keep an eye out because there'll soon be a way to do it explicitly (https://github.com/omcljs/om/issues/485 )

artemyarulin12:12:48

My read function is called two times with nil target and :remote one. I’m not using any remotes, should I somehow disable :remote target?

artemyarulin12:12:02

is there any performance implications because of this?

anmonteiro12:12:11

I don't think there's a way to disable that

anmonteiro12:12:19

it's just how Om works

anmonteiro12:12:31

if you don't have any remotes it won't do anything

anmonteiro12:12:52

not sure about performance implications but I'd say they're negligible

dnolen12:12:02

@artemyarulin: there will never be any way to control how many times read or mutate gets called

artemyarulin12:12:18

Trying to understand how to work with remotes. As I understood my send functions has to call cb arguments with new data. And this cb then forwards this data to my merge function? Is it so?

artemyarulin12:12:29

Sorry for the dumb questions simple_smile

danielstockton12:12:19

@artemyarulin: Pretty much. merge goes on to call merge-tree, merge-idents and migrate

danielstockton12:12:33

merge-tree adds the new data to your app state and migrate updates tempids

danielstockton12:12:02

you probably don't have to provide a custom implementation for merge, just :merge-tree and maybe :migrate

artemyarulin12:12:03

Hm, :merge and :merge-tree are different?

artemyarulin12:12:49

I guess I need :merge-tree in order to merge the new data into the right place in state

octahedrion12:12:08

hi, I need to use SVG's pattern, but Om doesn't have it (thought React supports it) -- how can I tweak Om to support it for my code ?

octahedrion12:12:18

(btw, I know about Sablono, but since I need to compose pattern with existing Om code, I can't see a way to use it)

octahedrion12:12:19

(because Sablono takes vectors but my Om code returns (svg #js {} (rect #js {} etc

r0man12:12:55

@octo221: Try to call js/React.createElement directly

dnolen12:12:48

@artemyarulin: implementing :merge means you want to take complete control over how merging happens

dnolen12:12:06

it exists for custom storage users i.e. DataScript or something else

dnolen12:12:28

if all you want to do is control how the data gets merged using the default db, :merge-tree is enough

artemyarulin12:12:17

oh, cool, thanks. When do I need to use :merge-idents?

dnolen12:12:58

only if you think you need more control over that

dnolen12:12:18

in general you don’t need to do any of this if you’re using the default db

dnolen12:12:43

:merge-tree is probably the only one people will normally supply themselves

artemyarulin12:12:55

Cool, it’s clear for me. Thank you!

chedgren14:12:27

How does the :keyfn of factory work? The examples have this line (def person (om/factory Person {:keyfn :name})), Do I basically give it a keyword in my map ?

dnolen14:12:33

@chedgren: any function works

dnolen14:12:38

it will be passed props

chedgren14:12:15

And it really helps if you add it to the right component. confusion lessened.

jannis14:12:55

@dnolen: I may have found a bug in normalization, where recursive joins break other joins. I find it hard to describe. Here's input data, UI (root component omitted) and query result data: https://gist.github.com/Jannis/e16dac5628ca7a0ef229 - note how in the query result, :parent is broken (a list of idents instead of the actual parent data) in one place but not in the other. It may be intentional and perhaps I'm doing something wrong?

dnolen14:12:27

@jannis: it’s intentional we don’t follow recursions

jannis14:12:12

Is there a way to make this kind of thing work (e.g. by making the read function smarter, which currently simply does {:value (om/db->tree query (get st key) st)})?

dnolen14:12:22

@jannis looking at your gist you obviously have a loop there

dnolen14:12:26

you don’t want stack overflow

dnolen14:12:57

so the question is … what is the behavior you want? simple_smile

jannis14:12:43

Yep, the data is a graph with cycles.

jannis15:12:23

I guess I could treat it as a tree, drop :parent and instead pass the parent down to children in render.

jannis15:12:11

That way they could refer to the parent but there would be no cycles in the data itself.

dnolen15:12:54

@jannis I could imagine adding support for using a number instead of ’… a la Datomic

dnolen15:12:04

to control the amount of recursion you get

dnolen15:12:45

I don’t know if that’s good enough for your usecase

jannis15:12:02

There's no fixed limit for the depth in my case but in reality the data won't be deeper than 3-5 levels.

jannis15:12:40

So yeah, that could help.

dnolen15:12:20

@jannis yes that’s what I mean

dnolen15:12:30

it’s not like you’re going to crawl the graph inside of a component

dnolen15:12:39

you just need to get far enough for it solve your problem

dnolen15:12:03

not sure when I will get to it, recursion support pervades the code base

dnolen15:12:10

so not a simple change

jannis15:12:19

I can imagine

jannis15:12:43

I'll see if I can find ways to avoid the data loop short-term; there are a few other places where loops exist as well and it might not be as easy there

dnolen15:12:00

I’ll probably take a look at it after error support and routing support

jannis15:12:07

The recusion limit support would solve all of those instantly though simple_smile

acron16:12:12

Am I correct in understanding that IDidUpdate does not get called after the initial render, only after subsequent renders?

acron16:12:37

Are there any 'events' that fire after every render, including the initial one?

acron16:12:00

I have read this document and so my suspicions are that there aren't

acron16:12:28

I was just wondering (hoping) I'd misinterpretted or something

anmonteiro16:12:33

componentDidMount for the initial render

anmonteiro16:12:42

componentDidUpdate for subsequent ones

acron16:12:55

Ok, thanks

artemyarulin16:12:19

is there any docs/examples about server streaming/server push?

anmonteiro16:12:58

just a placeholder in the wiki for now

artemyarulin16:12:11

Yeah, I found it already simple_smile

artemyarulin16:12:36

But is there API for that, does om support it already?

Tim16:12:00

so is om.next going to be moving off of react entirely?

anmonteiro16:12:49

@tmtwd: can you rephrase?

Tim16:12:12

is om.next going to be removing react from the framework?

anmonteiro16:12:22

not that I know of

anmonteiro16:12:54

I'm pretty sure Om will continue to be "A ClojureScript interface to Facebook's React."

anmonteiro16:12:23

@artemyarulin: I believe the API supports it already

anmonteiro16:12:28

personally, I haven't tried it yet, but I imagine it's not difficult

dnolen16:12:08

but the coupling may be made loose enough to enable server side rendering

artemyarulin16:12:23

@anmonteiro: OK, I’ll check the source code

anmonteiro16:12:51

I don't think you'll find anything particular to that use case in Om's source

dnolen16:12:01

@artemyarulin: streaming isn’t any different from writing send minus the send part

dnolen16:12:13

you just merge! in stuff

anmonteiro16:12:43

As David keeps saying, Om doesn't do anything, it's up to us to make it do what we want

artemyarulin16:12:51

So, just to clarify - my external code can change atom state and om-next will handle it?

dnolen16:12:13

I just said use merge! simple_smile

dnolen16:12:21

it’s what Om Next uses itself

artemyarulin16:12:50

ahh, merge! function from om

dnolen16:12:01

so no you don’t want to do stuff like arbitrary swap! unless you’re prepared to handle all the boilerplate yourself

dnolen16:12:49

I’ve tried to consistently dog food Om Next’s API so that people can re-use this tuff

artemyarulin16:12:12

Got it, cool. It should be quite easy to implement

paxan18:12:25

Is there explanation about how om/tempid is supposed to be used with a datomic-based remote? So far, I've been trying to read om's source code to figure that out. But I am a slow and inept at source code reading.

dnolen18:12:49

@paxan: om/tempid doesn’t really have anything to do with Datomic it’s just a generic thing

paxan18:12:01

is it meant to be playing well with mutation fns that on server side have :tempids { ... } produced by datomic?

dnolen18:12:28

it’s just a generic thing like everything else

dnolen18:12:46

you will need to do the mapping automation bits yourself

dnolen18:12:53

but of course that doesn’t require much effort

paxan18:12:31

so i need to implement mapping between tempids generated by om on client and resolved tempids produced by datomic, right?

paxan18:12:06

sorry, but I am not yet well versed in this system to grok this. I need some guidance simple_smile

paxan18:12:33

like om-datomic-tempids mapping for dummies simple_smile

dnolen18:12:24

walk the transact entity data using a state atom wrapping a map, everytime you encounter an om tempid replace with a datomic tempid add this mapping to the state atom

dnolen18:12:56

when you’re about to return the result back to the client, compute :tempids for each mutation using :result of each mutation

paxan19:12:55

I think I understand now, @dnolen. something like that?

(let [conn ...
      state ...
      tid->otid (atom {})
      tx (clojure.walk/postwalk
          (pseudo-fn "when you see om/tempid x, replace with datomic/tempid y, and assoc! y->x to tid->otid map")
          state)]
  (let [datomic-result @(transact conn tx)]
    {;; ... result to be returned to client, and:
     :tempids (into {} (for [[tid id] (:tempids datomic-result)
                             :let [otid (@tid->otid tid)]
                             :when (some? otid)]
                         [otid id]))}))

paxan19:12:00

it is simple once it was explained well. Thank you!

noonian19:12:30

@dnolen: can you send me a CA please?

dnolen19:12:49

@noonian: DM your email

tomc20:12:14

Seeking some help with normalization. I tried adding very basic routing to the Components, Identity, and Normalization tutorial. I split :list/one and :list/two into two separate routes, and the root component only includes in its query the query for the current route. So, assuming we start with the route :route-1, the first query looks like [:session/route {:list/one [:name :points :age]}]. This renders the initial page just fine. But when you try to nav to :route-2, the :list/two data isn't normalized. This is because the data is only normalized when we first call add-root!, and at that time, Om doesn't know anything about the :list/two query. I do not know how to either 1) normalize all the data upfront while preventing over-fetching or 2) normalize the data again every time the root query changes. Here's a gist with the differences from the tutorial marked: https://gist.github.com/tomconnors/c1cceaae84fd059e37a3

dnolen20:12:50

@tomc: remember that everything in Om Next is presented a la carte

dnolen20:12:20

if you have a bunch client side information normalize this stuff yourself if the default behavior can’t take care of it for you

dnolen20:12:36

as much as possible Om Next exposes it’s own machinery as official API

dnolen20:12:41

use the lego blocks!

tomc20:12:40

@dnolen: So in this situation I would just want to normalize the data myself before add-root!ing?

tomc20:12:55

Awesome, thank you.

dnolen20:12:56

if you supply an atom for :state Om Next won’t touch it

dnolen20:12:07

auto-normalization only occurs if you use plain data

dnolen20:12:22

or if you explicitly request :normalize true

tomc20:12:18

ah, I see, I can just use tree->db along with a query that unionizes the queries of every possible route. cool!

johannjohann22:12:26

hey david have you poked around with how react native mounted components behave?

dnolen22:12:24

@johannjohann: if that’s directed at me, no I haven’t looked at React Native at all

dnolen22:12:42

and I don’t really have time for it to be honest

johannjohann22:12:47

totes understand

dnolen22:12:01

but PRs are welcome to make it work, whatever the issues are I can’t imagine they are very significant

dnolen22:12:18

Om Next is already decoupled from React DOM more or less

artemyarulin22:12:27

there is a channel #C0E1SN0NM and people there discuss RN + Om-next sometimes

tomc23:12:19

@dnolen: I was able to get routing + normalization working based on your earlier advice, but now full-query is not working for any components other than the RootView. Looking at the indexer's :class-path->query map, the expected path (om-tutorial.core/RootView om-tutorial.core/RouteTwo om-tutorial.core/Person) is missing, but (om-tutorial.core/RootView om-tutorial.core/Person) is present. Why would the in-between component be missing?

dnolen23:12:33

indexing only considers components that actually have queries

dnolen23:12:02

if RouteTwo actually has a query and it wasn’t indexed correctly it’s because you’re doing something that’s not supported

dnolen23:12:23

i.e. stealing queries from another component or something like this

tomc23:12:44

I am using a subquery that references another component's query like in the RootView of the tutorial. I basically just took the tutorial's RootView's query and divided it between two subcomponents.

dnolen23:12:14

will need more information

dnolen23:12:24

no idea what you are doing or how you are trying to do it

dnolen23:12:31

should be minimal and I can take a look