Clojurians
#om
<
2016-03-01
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

tawus03:03:40

If I have a query [(:list-with-args {:arg ?arg})] in a component and there is any mutation for this component, should I expect a read to be called for :list-with-args ?

currentoor05:03:04

How do I make my project depend on the most recent version of om.next?

tawus05:03:07

most recent version or snapshot ?

tawus05:03:49

Are you using lein ?

currentoor05:03:04

nope, boot but it’s probably similar

cjmurphy05:03:28

Clone the repo then install to .m2. With lein this would be lein install. (sorry busting in!)

tawus05:03:37

[org.omcljs/om "1.0.0-alpha30"]

tawus05:03:46

for recent version.

cjmurphy05:03:59

[org.omcljs/om "1.0.0-alpha31-SNAPSHOT"]

tawus05:03:11

and for snapshot what @cjmurphy said :simple_smile:

currentoor05:03:23

i see, and what does [org.omcljs/om "RELEASE”] do?

cjmurphy05:03:27

:simple_smile:

currentoor05:03:40

ok so there are four ways to do this lol, [org.omcljs/om "1.0.0-alpha30”], [org.omcljs/om "1.0.0-alpha31-SNAPSHOT”], [org.omcljs/om "RELEASE”], and what @cjmurphy said. The first is the most recent version, the second is the latest snapshot (what’s a snapshot?), the third and fourth are the same as the latest snapshot?

currentoor05:03:47

is that correct?

cjmurphy05:03:04

I don't know what the RELEASE is. But SNAPSHOT and what I said are the same thing.

cjmurphy05:03:43

And the alpha30 is like the current last release that DN chose.

cjmurphy05:03:23

alpha30 will be more stable.

currentoor05:03:57

@cjmurphy: ah i see, thanks

cjmurphy05:03:13

I only just saw your lol :simple_smile:

currentoor05:03:39

and the best way to find the latest release is in the project.clj file in the om repo?

cjmurphy05:03:02

Yes, that's how I found it.

currentoor05:03:09

cool, thanks

cjmurphy05:03:46

With boot at least you won't have to remember to lein clean, lein deps projects that refer to om after you install it - well that's the theory with boot I think.

currentoor05:03:05

so i’ve heard

currentoor05:03:15

hopefully that’s true

george.w.singer06:03:13

Should I have any problems running a server-side om-next remote parser with a clojurescript back-end targetting node.js/express.js? All of the tutorials I've seen so far are using pure Clojure on the back end. I still haven't wrapped my mind yet around how this part of the Om Next puzzle works.

artemyarulin07:03:09

@george.w.singer: Haven’t seen anything like that, but using CLJS in Node is not a problem, so it should work

george.w.singer10:03:03

@artemyarulin: sounds good. Are there any om.next libraries I have to explicitly import into nodejs/express (via cljs) on the backend? Or is it all manual?

artemyarulin10:03:18

@george.w.singer: Hmm, not sure. Maybe you can get some info here https://github.com/omcljs/om/wiki/Server-Side-Rendering and referenced Foram therem. It’s about different thing, but could be a place to start

jlongster14:03:52

@george.w.singer: I use ClojureScript on the server with express and it should work fine with no changes, just import om normally

thomasdeutsch14:03:07

for performance reasons, i would like to store some data that is calculated during the rendering phase. so, when the next rendering occures, the render-fn will look if there is some cached data before doing the calculations again. I was thinking about using a second state atom that will only host the cache-data (without any connection to the app-state). Is this a bad idea?

danielstockton14:03:23

not sure i understand, don't see why you couldn't have a separate cache that is a function from state -> cached value

danielstockton14:03:32

seems orthogonal to anything om

thomasdeutsch14:03:25

if the cache is a part of the state, i would have a rerender if the cache is updated. or can i prevent any rerender on a transaction?

danielstockton14:03:45

why would the cache be a part of the state?

thomasdeutsch14:03:45

(or ... prevent reads)

danielstockton14:03:52

i think that om's involvement stops once it passes the correct props to your render function

danielstockton14:03:57

what you do in render is your own business

thomasdeutsch14:03:57

Ok... yes. I was thinking the same.

jlongster15:03:37

How is :om.next/queries managed? I see that it's added to in set-query!, and removed from in componentWillUnmount, but isn't there somewhere else that adds to it?

anmonteiro15:03:26

@jlongster: are you asking that because you're seeing a nil value for that entry?

jlongster15:03:37

no, I don't see any problems but I noticed that my parser function was being run at a weird time and I realized that componentWillUnmount modifies the state. I'm dynamically displaying various children that have queries, so when they are unmounting it updates that key, but I'm worried that new children aren't updating it

jlongster15:03:41

so I may hit a bug later

jlongster15:03:56

I'm using a virtualization library that only displays a subset of a large list in the DOM, and each of those rows has a query. It seems to work pretty well, but just wanted to make sure

anmonteiro15:03:28

@jlongster: queries are only stored in the state if you explicitly set them for a mounted component

jlongster15:03:30

example code if it helps that renders the VirtualScroll element: https://gist.github.com/jlongster/e9d8ea3a06f8dc3438f6

jlongster15:03:32

@anmonteiro: ah ok. will the swap! in componentWillUnmount always trigger the watch (which schedules a rerender) even if it didn't change the data?

anmonteiro15:03:19

@jlongster: I don't know, but that's something I can try in a second

anmonteiro15:03:34

it will however trigger the watch in the first unmount

jlongster15:03:06

"first unmount"?

jlongster15:03:30

I'm trying to avoid unnecessary rerenders

anmonteiro15:03:46

when the key is not even there

anmonteiro15:03:58

(swap! (atom {:a 1}) update-in [:b] dissoc 3)
=> {:a 1, :b nil}

anmonteiro15:03:24

it's how update-in works

jlongster15:03:53

the keys of :om.next/queries are component instances, correct?

jlongster15:03:16

it will always be the "first unmount" then :simple_smile:

anmonteiro15:03:19

if you didn't set the query for an instance there will be no entry under ::queries

jlongster15:03:45

can we first check to see if this# is in :om.next/queries before dissoc-ing it?

jlongster15:03:49

that would solve it

anmonteiro15:03:33

it probably would

jlongster15:03:59

ok I'll make a PR

anmonteiro15:03:24

@jlongster: looks good, does it solve your problem locally?

jlongster15:03:32

yep! all smooth now!

grzm15:03:27

anyone have or know of an auth/session example using om next?

danielstockton15:03:20

gzrm, have you got a particular problem?

danielstockton15:03:42

i hope to tackle auth quite soon

grzm15:03:32

I'm just too new. Tackling a lot of new things at once. I'm trying to determine if I should use a separate remote for login, or maybe even just a normal POST to a login resource, or if I should try to handle it with a mutate like [(login/submit creds)]

danielstockton15:03:10

I would handle it through a remote mutate, which returns the user on success and merges it into your app state. Then you can check for this user in your app-state to determine if you're logged in/out.

nha15:03:46

Is it normal if https://github.com/swannodette/om-next-demo doesn't allow adding new TODOs ?

grzm15:03:48

That's the way I'm working through right now. Actually, it's server-side stuff I'm struggling with (bidi/friend/carmine), not om-specific

grzm15:03:59

@nha: it's a non-working example

grzm15:03:23

@nha: I tried for quite a while to get it to work before someone told me the same thing :simple_smile:

nha15:03:42

Well, thanks for saving me some time ^^

grzm15:03:05

Think dnolen would accept a pull request adding such an annotation to the readme?

grzm16:03:15

@dnolen: I've submitted a pull request to update the README for om-next-demo to note that not all the features work. I know this would have helped this newbie (me) quite a bit of time and I've seen others ask similar questions regarding the om-next-demo: https://github.com/swannodette/om-next-demo/pull/3

rauh16:03:48

@grzm: Def. use a separate url/remote for login stuff, at the very least you want to limit the requests per IP with something like nginx. Or of course you can do that within the server if you have the time to implement such logic.

dnolen16:03:38

@grzm: OK, but not a priority for me

grzm16:03:02

@dnolen: understood.

artemyarulin17:03:24

Most of the articles and wiki examples mentioned that you can (or probably would) edit the AST for remote fetch. Is it OK to change :params as well?

dnolen17:03:59

anything about the AST is OK as long as you’re fine with the consequences

dnolen17:03:21

as in we don’t really care what people do - it’s meant to be flexible for a reason

artemyarulin17:03:35

@dnolen: Got it. BTW - just wanted to say thank you for om-next: learning curve is a bit of a problem, it’s not easy, but once I got it - it’s indeed very simple and powerful at the same time

dnolen17:03:52

@artemyarulin: glad to hear it!

jlongster17:03:57

@tony.kay: I'm starting to see the benefits of transacting to perform remote fetches. it would solve a problem I have right now. did you mention that you talk about it in your tutorials? I don't see anything like it in there

jlongster17:03:18

I want to blow away the result of a previous remote fetch so that my component knows that it's loading again. right now I just check if the data exists at all, and if not I assume it's loading. but I can't blow away the current data by just changing query params.

tony.kay17:03:02

So, no it is not in the tutorials...the tutorials are Om. The extensions I'm talking about are part of the stuff I'm trying to get open-sourced with my company....having lunch with the CTO today...so may be able to share very soon :simple_smile:

tony.kay17:03:11

@jlongster: ^^^

tony.kay17:03:28

Framework stacked on Om Next

jlongster17:03:53

well, I see how it would work so I'll probably just implement a simple version for now

artemyarulin18:03:08

hm, what the purpose of :query-root in context of read parser and remote calls?

jlongster18:03:57

@artemyarulin: it marks the ast so you can use process-roots in your send function, which transforms the query to make all the query roots top-level and sends off those to the server instead of the raw UI query

artemyarulin18:03:51

hm, any examples of this? I’m having a problem that send function receives really a big query, while real data it cares about far deep down. I guess process-roots solves exactly this issue?

jlongster18:03:57

assuming you've marked certain parts of the ast with query-root

artemyarulin18:03:13

something like that?

{:remote (assoc ast :params (find data :path) :query-root true)}

tony.kay18:03:07

@anmonteiro: See a regression in the indexer when flowing through the code you changed for dyn queries. Cannot read property 'call' of null from the last line shown in the snippet below. Thoughts?

jlongster18:03:26

@artemyarulin: did you mean assoc-in?

artemyarulin18:03:20

@jlongster: Well, I didn’t, but I’ll try :simple_smile:

artemyarulin18:03:02

well, actually from tests in om-next:

(defmethod precise-read :real/key
  [{:keys [ast] :as env} _ _]
  {:remote (assoc ast :query-root true)})

jlongster18:03:46

@artemyarulin: right, you just mark any point with :query-root, usually you are recursively calling the parser and look for specific keys and then you can do that simple assoc

tony.kay18:03:52

@anmonteiro: Hm...maybe not....strange. Let me look more

artemyarulin18:03:49

@jlongster: Yep, this is exactly what I’m doing:

(defn read [{:keys [query data state target parser ast] :as env} key params]
  (case key
    :current {(or target :value)
              (assoc ast :params (parser (assoc env :data (get-in @state (get @state key))) query target))}
    :content (if-let [c (get data key)]
               {:value c}
               {:remote (assoc ast :params (find data :path) :query-root true)})))

jlongster18:03:04

oh, I misread your code before, I think that works yes

artemyarulin18:03:12

thank you for your help!

jannis19:03:06

Does query not support joins on link properties? E.g. (query [_] [{[:current-user _] [{:profile (om/get-query UserProfile)}]}])

hueyp19:03:08

I ran into some indexer bugs with that but I think @anmonteiro fixed them on master

tony.kay19:03:38

@anmonteiro: Actually, it does seem to be a regression when using links (`[:x '_]` in joins). My app begins working again if I change the line mentioned above to: (if (or (nil? loc) (empty? path)) (line 108 of commit 8f31b)

tony.kay19:03:08

That is probably not the correct patch...I'll see if I can write a test that demonstrates the problem. It shows up when indexing on add-root

stephenway19:03:54

Hello, looking for help with svg <use> tags in Om (dom/svg #js {:viewBox 0 0 100 100"} (dom/use #js {:xlinkHref "/path/to/icon.svg"})) gives me React.DOM.use is not a function on Om Next 1.0.0-alpha.30 with React 0.14

fasiha19:03:23

@stephenway: <use> tag isn't supported by React: https://facebook.github.io/react/docs/tags-and-attributes.html#svg-elements and therefore won't work with Om

blissdev19:03:50

@stephenway: you can get around it with dangerouslySetInnerHTML which isn’t ideal, but works

jlongster19:03:48

how do people handle parameterized queries when using db->tree? there's no way to customize a parameterized piece deep in the query there

artemyarulin19:03:43

Does anyone have an example of recursive parser for remotes? As far as I understood :remote value has to be either true or AST, isn’t it? So basically I should call parser recursively and then update AST with returned query?

hueyp20:03:06

the @tony.kay tutorials have parsing examples for recursive parser

artemyarulin20:03:54

@hueyp: Thank you!

anmonteiro20:03:51

@tony.kay: let me run your failing case

anmonteiro20:03:36

but I think patching query-template is usually not the way to go

anmonteiro20:03:27

@tony.kay: it's a regression of #620, not #612

anmonteiro20:03:52

while we want to save the link's (e.g. '[:a _]) props as :a, the query path still needs to be [:a _]

tony.kay21:03:49

@anmonteiro: Thx...I didn't have time to understand the algorithm...figured you'd know the patch :simple_smile:

anmonteiro21:03:23

@tony.kay: where are you returning remote mutations' tempids?

tony.kay21:03:45

from action, then plumbing it up to make it appear on the client correctly

anmonteiro21:03:26

something tells me this should be (comp :tempids :result second)

tony.kay21:03:54

according to David, the way it is is correct, but I agree with your assessment...I've had this discussion :simple_smile:

tony.kay21:03:51

side-effects go in action: tempid generations are side-effects...ergo....

anmonteiro21:03:54

I'd love to know the explanation behind this one

anmonteiro21:03:02

@dnolen: if you could pitch in?

jlongster21:03:34

I'm having a very hard time figuring a good way to do this, unless I refactor my whole remote fetching mechanism to be more like Tony's (remote fetches happen through transact!). I'm fetching a subset of a list from the server and displaying it, and later I'm fetching a different subset, but I want to "blow away" the old data from local state because the component immediately rerenders after using update-query! to change the params, but it's rendering the old data for 1s before the new results come in... (for various reasons, rendering the older data for the 1s is wrong)

dnolen21:03:07

yes tempid generation is a side effect

dnolen21:03:17

you have to organize your code around that like any side effect

anmonteiro21:03:25

@dnolen: what I meant was: should we return the tempids from the server where the default-merge expects them to be?

dnolen21:03:47

I don’t know what that means

anmonteiro21:03:57

atm I'm returning them under {'my/mutation! {:result {:tempids {...here...}}}}

anmonteiro21:03:24

but Om's default-merge expects them to be one level above

dnolen21:03:48

:tempids needs to be under :value

anmonteiro21:03:44

oh ok, that would make Om know about them, right

anmonteiro21:03:14

but I only have my tempids after :action is ran

dnolen21:03:27

you need to be OK with post processing

dnolen21:03:32

mutations are flat so this isn’t a big deal

anmonteiro21:03:56

I'm not sure I follow

dnolen21:03:19

walk the result to create :tempids after doing everything

anmonteiro21:03:06

I don't have a problem with that

anmonteiro21:03:23

just means that I can't return it in :value

dnolen21:03:37

because you are rewriting server response

dnolen21:03:51

you cannot do it in the body of your parser fn

dnolen21:03:58

but that’s not really a big deal

anmonteiro21:03:22

that's what I meant, and I agree. No big deal

dnolen21:03:56

@anmonteiro: other things have similar problems

dnolen21:03:12

all :results could be futures

dnolen21:03:15

which you need to force, etc.

anmonteiro21:03:12

makes sense. What got me into this confusion was my assumption that tempids should be returned in :result

anmonteiro21:03:21

I can see that my logic was flawed now :simple_smile:

dnolen21:03:03

non-obvious - keeps coming up so obviously we need to be extra clear about this in multiple places

anmonteiro21:03:29

@dnolen: I can write something up in the FAQ

dnolen21:03:46

@anmonteiro: that would be helpful, also a good case for an invariant :wink:

dnolen21:03:13

if the :results is a map and it has :tempids entry something is probably up

dnolen21:03:24

though this is server-side

dnolen21:03:32

and maybe the invariant stuff isn’t suited for that

anmonteiro21:03:46

@dnolen: I don't think invariants are suited for server-side code

anmonteiro21:03:02

and I also don't see the problem of having :tempids in the :result

dnolen21:03:19

it’s not so much a problem as 50/50 unintended

anmonteiro21:03:37

from what I understood, I need to return them in the result and do post-processing on the result map

dnolen21:03:54

ah right yes

dnolen21:03:00

the tempids from some other thing

stuartsierra22:03:20

In Om.now, when you need to load some data in order to render a component, at what point is it appropriate to call the code to request that data from the server?

anmonteiro22:03:07

@stuartsierra: I've gotten away with doing it in IWillMount

tony.kay22:03:56

So, that clears it up for me better. Tempids have to be in result because it is a side-effect thing; however, since they could be in a future (they are not a tempid yet) you have to assume that post-processing might be required.

anmonteiro22:03:58

but you need to be OK with data not having arrived when the component renders

tony.kay22:03:53

So, if anything, I might advocate that the parser not be involved in :tempids at all. There isn't any way to ever emit them there. From everything I've seen, it is always post-processing that puts them in the correct place (by reading :result) for client consumption.

dnolen22:03:36

that’s a good point

tony.kay22:03:46

I've written all of our plumbing to just look for :tempids in :result and lift them, since we do the xactions synchronously on the server. Perhaps that should be the default in Om? Easy enough to do something else (e.g. not return them as :tempids)

stuartsierra22:03:00

I don't really know the significance of DidMount vs WillMount

tony.kay22:03:09

that would give both options, but cover the common case clearly

anmonteiro22:03:12

@stuartsierra: yes, that's the approach I've used before

anmonteiro22:03:45

but once I discovered I could do it in willmount I started doing it there

tony.kay22:03:05

Oh wait...the server calls the parser...so post-processing is needed, perhaps.

anmonteiro22:03:07

componentWillMount is ran before the render. componentDidMount is ran after

stuartsierra22:03:31

possible explanation https://github.com/tessalt/ds9-episodeguide/issues/2"it appears that until a component is "mounted," updating the state won't cause a redraw."

anmonteiro22:03:21

thanks, wasn't aware

stuartsierra22:03:22

Thanks @anmonteiro

george.w.singer22:03:17

Trying to require [om.next.server :as om] via cljs on the backend (targetting nodejs) yields an error. Is there anything special I have to do to use this?

jlongster22:03:36

@george.w.singer: just require [om.next :as om]

george.w.singer22:03:04

I'm assuming this is because all I really need from Om Next on the backend is a parser to read the remote query, do something with it, and spit a response back to the client. The parser logic will be the same on the server as it will be on the client. Hence all I need on the server is the same om.next library that's being used on the client. Is this about right?

anmonteiro22:03:51

@george.w.singer: partly. also because om.next.server is a Clojure file, not a Clojurescript one

george.w.singer22:03:07

What is om.next.server used for then?

anmonteiro22:03:13

Clojure backends

bnoguchi22:03:05

@jlongster: Where are you calling update-query! from? From inside a transact handler?

jlongster23:03:28

@bnoguchi: no, in an event handler that another React component fires (that is ultimately fired from a DOM event)

jlongster23:03:57

I think I figured it out though, will require some re-working but I don't actually want to blow away the old data

bnoguchi23:03:27

@jlongster: I was going to suggest adding in one layer of indirection. Instead of calling update-query! from within the event handler, move it into a new transact handler and write some fetching status to the state just before you call update-query! Then add that status to the relevant component's query, so you can conditionally render based on your results and the status you’re now querying locally from your app state.

jlongster23:03:36

@bnoguchi: I like that idea, but what would I call update-query! on? I don't have a reference to the component in the mutate function

bnoguchi23:03:49

@jlongster: I think you do have access to the component. transact is called with a component always

jlongster23:03:13

oh, it's in the environment or something?

bnoguchi23:03:14

@jlongster: I believe you can access it in your mutate handler’s env arg

jlongster23:03:20

oh, neat, didn't know that

bnoguchi23:03:21

(:component env)

anmonteiro23:03:22

@dnolen: I've been getting into an edge case which I'm not sure is even worth solving. I'll lay it here anyway Because React reuses component instances, there's a mounted component that doesn't change ident when my browser route changes

anmonteiro23:03:26

or rather... because the component doesn't unmount & re-mount, the indexer doesn't get updated with the new ident

anmonteiro23:03:33

I need to verify which is the case

anmonteiro23:03:36

it's the 2nd case. the indexer doesn't update, but the ident does because props have changed