Fork me on GitHub
#om
<
2016-03-11
>
seanirby00:03:54

[{:foo/list [:foo/name]}]
this is the correct query to get all the :foo/name values for all the elements referenced by :foo/list right?

seanirby00:03:43

im wondering why doing (om/db->tree [{:foo/list [:foo/name]}] @app-state @app-state) produces the result {:foo/list [[] []]} . I can tell that it's correctly picking up that there's two elements in the :foo/list vector, but it can't seem to find :foo/name property

seanirby00:03:31

OK, If I add an Ident to the Foo class then it works. But why?

chrisfarber00:03:45

I’m just getting started myself, so I’m probably not much help – but, I’d suspect it has something to do with normalization

chrisfarber00:03:01

question of my own: What conditions trigger om next to re-fetch remote data for a query it has already fetched data for?

ethangracer00:03:50

@seanirby om/db->tree assumes that you are using the default om database format. so you need to have idents on components so that it can destructure your flat app state into a tree

ethangracer00:03:23

@chrisfarber: om should re-fetch on read where :remote true appears in the map that you return on read

ethangracer00:03:48

shouldn’t matter if it’s already fetched it

seanirby00:03:27

ethannavis: so in other words, components which are part of collections need to have an ident?

ethangracer00:03:55

if you want to normalize them using om’s default database format, yes

ethangracer00:03:16

which you will almost certainly want to do

ethangracer00:03:41

the nice thing about om is that it gives you flexibility not to use its default database format if you decide that you don’t want to

ethangracer00:03:55

though there is significant plumbing built-in to help you use it

seanirby00:03:28

ethannavis: regarding the 'plumbing' i know of the reconcilers data normalization, component Ident's, and db->tree. What else is there?

ethangracer00:03:44

those are the biggest pieces… the only other one I can think of is merge!, which just uses om/tree->db

urbanslug07:03:37

What is a “component” in Om?

urbanslug07:03:06

Where can I find something that doesn’t assume I know Om or what components mean and what stuff like reify mean?

urbanslug07:03:31

I can’t find a beginner resource for Om. Even the basic tutorial assumes React knowledge or something.

urbanslug07:03:39

Om is so interesting yet unreachable yeeesh

cjmurphy07:03:37

@urbanslug: Anything that starts with defui is a component. Behind the scenes it happens to be a React component, but that's largely irrelevant for getting things working. I think a good place to start is just there, with a component being passed props. Look at a devcard of an Om Next component from a project, and try to create a component yourself - passing in a hash-map like devcards do (that's all that props is - a hash-map where the keys are keywords). Just try to do a render function - and see something in your browser. Queries, idents, default db format, all those things can come later once you've got something on the screen. That's one way to start...

urbanslug07:03:37

cjmurphy: What is a react component though? and props?

urbanslug07:03:49

cjmurphy: Do I need to learn React first?

cjmurphy08:03:12

Don't need to learn React. The whole props thing is all about immutability. You let React create components for you when it decides the props have changed, something like that...

cjmurphy08:03:50

Actually Om Next might be doing that part and React is all about the diff-ing. Not sure! 😜

urbanslug08:03:12

cjmurphy: I wish you’d mentioned my username. I’ve been waiting for this reply for long.

urbanslug08:03:43

props are which immutable thing now? props are a data structure?

urbanslug08:03:14

I haven’t actually seen any code with defui

cjmurphy08:03:41

props are just a hashmap.

cjmurphy08:03:36

You can't change a component - a new component comes along - that's immutability.

urbanslug08:03:39

and clj(s) data structures are immutable so this is maintained in Om I see

urbanslug08:03:50

but not so in JS

urbanslug08:03:04

I wonder why we have new terms for this.

urbanslug08:03:27

Like today I learned that maps are called objects in JS. That is the height of misleading terms.

cjmurphy08:03:46

The term props comes from React - each component has props and children - so same with Om Next components.

cjmurphy08:03:30

Well map is overused - that's why I hope to usually say hashmap when referring to data.

urbanslug08:03:48

Uh final question, this https://github.com/omcljs/om/wiki/Documentation doesn’t include functions like render

urbanslug08:03:56

Where can I read about them?

urbanslug08:03:07

I have no idea what render is really doing.

cjmurphy08:03:30

Be careful to know what is Om Next and Om Now (or Prev). defui is your guide. You were reading about the prior Om. I made that mistake at first. Trouble is it is all on the same website.

cjmurphy08:03:05

@urbanslug: that reference you gave was to Om Previous.

cjmurphy08:03:08

render is what puts your html on the web page - that's prolly all you need to know 😜

cjmurphy08:03:23

It is the only way to get visual feedback.

urbanslug08:03:42

cjmurphy: hahah thanks for the help. I guess I have to work towards migrating this app to Om Next on top of understanding Om

urbanslug08:03:00

I approve of your emoji usage simple_smile

cjmurphy08:03:34

Actually I copy my emoji usage from someone here, but he didn't put a ®️ on it so I'm okay...

cjmurphy08:03:25

I hope @hueyp ^^ 😅

raphael10:03:13

Hello, mutation functions need to return a map {:value ... :action ...} I don't understand the purpose of the :value key. Somebody can help me? simple_smile

raphael10:03:09

I mean, after a mutate (if I understood) the reconciler merge the new value in the state so why need I a return :value

iwankaramazow10:03:37

@raphael: from the quick start tutorial:

Mutations should return a map for :value. This map can contain two keys – :keys and/or :tempids. The :keys vector is a convenience that communicates what read operations should follow a mutation. :tempids will be discussed later.

raphael10:03:58

Hmm but I don't understand, if the data is updated, my component will apply an automatic read no?

iwankaramazow11:03:09

yes, but if you need to re-read keys that aren't part of the component's query initiating the transaction, you need to explicitly tell om

iwankaramazow11:03:42

section: Why is my component not rerendered after transact!?

iwankaramazow11:03:35

however I'm not 100% sure if :keys work as the tutorial says. I'm putting the re-reads straight into my transaction query

iwankaramazow11:03:10

example: [(mutate) :other-key]

iwankaramazow11:03:21

if I want to re-read :other-key

urbanslug11:03:56

cjmurphy: props is short for properties 😄

raphael11:03:42

Yes I think it is more nice, since if I don't want to say to my mutation function "don't forget to re-read x y z for my components!" mutation functions don't need to know anything about UI logic. am I wrong?

urbanslug11:03:52

AFAI can tell it’s an immutable prop from Om

anmonteiro11:03:44

@raphael: :value :keys in mutations are just convenience.. The :keys vector is a convenience that communicates what read operations should follow a mutation.

anmonteiro11:03:55

as stated in that sentence

anmonteiro11:03:12

the "communicates" there means person communication, not machine communication

anmonteiro11:03:20

i.e. documentation

anmonteiro11:03:48

so that e.g. a developer that needs to run a mutation written by another team member knows which keys to re-read

urbanslug11:03:53

This is what I think component is: In Om “component" is a term to mean a piece of encapsulation that contains mutable or immutable piece of UI

urbanslug11:03:05

Something like a html element

cjmurphy11:03:00

@urbanslug: https://clojurians.slack.com/archives/om/p1457694320004941 - that is still Om Previous. Best don't read it or at least be aware - cursors are Om Previous.

urbanslug11:03:42

cjmurphy: So I should start reading Om Next docs instead?

cjmurphy11:03:56

I think so yes.

urbanslug11:03:04

But code I am maintiaining or yet to port is in Om Now

urbanslug11:03:18

Okay hopefully docs there are better let me look at it.

cjmurphy11:03:36

Well I have to unthink so 😝

urbanslug11:03:58

I wonder whether I have to rewrite tests.

cjmurphy11:03:19

@raphael: See first pinned item for this channel.

iwankaramazow11:03:46

@anmonteiro: I noticed Om's source is mostly one ns, is there a particular reason for this? I'm going from a javascript background, where they make different files/different modules as if it's breathing air

anmonteiro11:03:50

@dnolen: I'm going to need access to normalization in the server, I was wondering if I could work on #398 ("normalization functionality should be accessible to server side code") It's really just code re-org, I'm thinking about having a om.next.impl.db namespace with tree->db and db->tree that both om.next and om.next.server depend on

anmonteiro11:03:26

@iwankaramazow: just how clojure namespaces are organized in general

anmonteiro11:03:20

I think at some point some stuff is going to be taken out, as I just asked David about the normalization stuff

iwankaramazow11:03:04

ok, thanks for the response!

tawus11:03:14

If one has to use autocomplete feature of https://github.com/JedWatson/react-select with om.next how should one proceed ?. For autocomplete the react-select component is passed a loadOptions callback which takes as input, the input string and a callback. The callback has to be called with the option-data from the server.

george.w.singer14:03:30

Consider the query: [(:some/key {:param :foo})]. How does the parser know whether this is a read with params or a mutation with params?

george.w.singer14:03:43

Ok. So in all cases reads are forced to have keywords, while mutations are forced to have symbols? Is that a datomic pull syntax custom?

anmonteiro14:03:56

@george.w.singer: Datomic pull doesn't define mutations

anmonteiro14:03:08

see the "Pattern grammar" section

george.w.singer14:03:44

looks like it doesn't define reads either?

anmonteiro14:03:29

I'm not sure what you mean

anmonteiro14:03:54

What I meant by it not defining mutations is that everything is a read

jlongster14:03:56

@george.w.singer: it probably came about because mutations look like function calls [(call-this-function ~params)]

addywaddy15:03:52

in om/now, components could be have their initial-state set via the init-state key. What is the best way to acheive this in om/next? Via om/computed?

anmonteiro15:03:38

@addywaddy: there's initLocalState

anmonteiro15:03:08

(defui X
    Object
    (initLocalState [this]
      {:a 1}))

addywaddy15:03:48

Hi @anmonteiro yeah, I’m using that. I want to set a number of components as being editable by clicking a link on their parent component. My solution so far has been mapping (value (om/computed props {:editable? editible?})), where editable? is the local state of the parent component. But this feels wrong.

addywaddy15:03:22

OK. I was just surprised that the computed part is present in (om/props this) too, so I’m having to dissoc :om.next/computed before transacting my changes.

anmonteiro15:03:16

Why do you need to dissoc?

addywaddy16:03:29

@anmonteiro: Sorry - missed your reply. I was transacting the props merged with the updated value, and so didn’t want to store the values under `:om.next/computed in the DB, but I’m being more explicit now about what is being updated.

drcode16:03:28

Hi, I have a child component, and when I do (om/path this) inside it I get nil and this is making the component behave incorrectly. Anyone have any tips as to why a child component might end up with a corrupt path and how to troubleshoot it? Thanks!

anmonteiro17:03:22

@drcode: 1. path is private, I'm curious why you would use it?

hueyp17:03:52

I think it gets path from path-meta?

anmonteiro17:03:04

2. it will be nil if you are passing e.g. {} as props

drcode17:03:01

@drcode: I'm not using it, my app is just breaking and I've narrowed it down to the path being broken

hueyp17:03:21

sure its path and not class-path?

anmonteiro17:03:45

a nil path will break things

hueyp17:03:55

@anmonteiro: is path from path-meta? so if you modify the props in some way that would lose metadata?

drcode17:03:13

@hueyp: Haven't studied class-path yet, all I know is I have a nested component with props.omcljs$path = null

anmonteiro17:03:33

@drcode: hrm, do you have a list in the app state?

anmonteiro17:03:39

or just vectors & maps?

drcode17:03:06

@hueyp @anmontiero: Thanks, sounds like clobbered metadata is where I need to focus my attention

drcode17:03:24

@anmonteiro just vectors and map

hueyp17:03:03

yah, I think I just do get to pass props from parent to child but I could see maybe if you do some processing on them first? (which might be a bad idea?)

anmonteiro17:03:09

@drcode: if you are putting metadata in props, make sure to vary-meta, not with-meta?

drcode17:03:52

Stupid question: If I create a component whith om/factory, I'm allowed to use that multiple times in my UI, right?

drcode17:03:24

Thanks, you guys are super helpful, I'm sure this info will help me resolve my problem!

anmonteiro17:03:45

I'm curious about the root cause if you end up finding it

drcode17:03:17

@anmonteiro: Your hunch was correct... I had a key in the state that didn't contain anything yet, but instead of initializing it to {} I just didn't bother defining it. Simply initializing it with {} fixed my problem. It seems rather counterintuitive that having a missing key in the state would cause a UI element to forget its path, might be good to have an error message for such situations.

hueyp17:03:39

wow, nailed it

hueyp17:03:45

gg monteiro!

peeja21:03:41

Hmm. Some of our data comes from Pusher channels, which we have to subscribe to and unsubscribe from as the user navigates. It occurs to me that the set of channels we need at any moment can be derived from the component queries. Is there a good place to notice that the queries have changed and recalculate which Pusher channels we should be subscribed to?

peeja21:03:48

Is that something parser code would do?

dnolen21:03:32

@anmonteiro: can we rebase the PR for 650? thanks

anmonteiro21:03:11

@dnolen: definitely. give me a few minutes

anmonteiro21:03:36

btw, did you see my question wrt. #398 (server side normalization) earlier?

franz22:03:45

Hi! if somebody has some spare time, I am fighting with the render hints of om/transact! which are causing the parser to be executed several times

franz22:03:11

I'm not sure whether my understanding is off or if I'm bumping on an issue

franz22:03:45

I have a 2 independant "leaf" components of my tree relying on the same underlying value, so when I'm updating that value I'd like to re-render everything

franz22:03:03

the transact function is called from one of those

anmonteiro22:03:16

@franz: the parser is run once for local reads and once for every remote

franz22:03:31

I don't have any remotes here

hueyp22:03:45

it transforms simple read-keys in the transact!

anmonteiro22:03:02

there's always one implicit remote

hueyp22:03:05

so any component with a :test prop will result in a full query being created as a read

franz22:03:52

mm, calling (om/transact! '[(test/weird) :test]) results in my read function being called 4 times in total

anmonteiro22:03:55

@franz: the component which transacts is queued for re-render. reading :test will queue the component which has that key

anmonteiro22:03:16

so 2 reads for the component which transacts, 2 reads for the component which has the :test key

franz22:03:21

but then calling (om/transact! '[(test/weird)]) should render twice

franz22:03:22

I'm trying to optimise that, because in the original project, I'm doing some "heavier" computation in the read function

franz22:03:55

but if I understand properly, the bottomline is that the read function should be really fast then

franz22:03:38

and all the heavy stuff should happen in the mutate functions

matthavener22:03:04

franz: I’d say so.. read/parser functions are synchronous so your UI will be blocked until a slow read finishes.. if the computation is really heavy you could ‘send’ to a webworker and then merge the result back in for a quick read

franz22:03:33

yeah i guess i should be able to turn that around somehow

franz22:03:38

thanks all for the help !

hueyp22:03:15

you can test if the first argument has a target key to avoid extra work

franz23:03:58

using force?

matthavener23:03:51

franz: in your reader, (:target env) will either be :remote or nil, so you could just ignore the read call if its :remote

matthavener23:03:40

or better, you can probably do :remotes [] in your reconciler config

franz23:03:24

I m not sure I understand yet why the parser is called once for each remote

matthavener23:03:10

franz: so you can send different remote queries to different remotes

matthavener23:03:18

or read locally

franz23:03:33

oh I thought that was all handled in one pass

franz23:03:26

cause the read function returns a map with one item per remote/local

franz23:03:24

now I've update my gist to output the target as well, and I get this

franz23:03:31

[3040.112s] [om.next] transacted '[(test/weird) {:test [{:comp1 [:key1]} {:comp2 [:key2]}]}], #uuid "13083851-f549-4b7d-938c-984f427f7185"
Reading test state for target nil
Reading test state for target :remote
Reading test state for target nil
Reading test state for target nil

franz23:03:19

using the reconciler :remotes [] setting eliminates the one line with :remote

franz23:03:35

but still 3 reads ..

franz23:03:40

so the read function is called one time for each remote cause you might want to get different parts of your tree, right?