Fork me on GitHub
#om
<
2015-11-29
>
artemyarulin07:11:19

Hi, does anybody know how can I attach static methods to the components? I would like to implement getDefaultProps but it has to be static, although defui expects to have protocol name after static keyword and I see no protocols for such thing

artemyarulin08:11:11

Came up with this solution so far:

(defui Webview
  Object
  (content-text [this] (or (:content-text (om/props this) "<b>Default</b>")))
  (render [this] (dom/div nil (.content-text this))))
Would be happy to see an easier or more appropriate way how to set default props

artemyarulin08:11:22

btw - it would be cool if defui would accept optional doc string as a second parameter, like defn and so on

Oliver George08:11:23

I'm wondering if this is a bug or confusion.

Oliver George08:11:46

If I modify the AutoCompleter example query it doesn't render after the send callback is called. Before (query [_] '[(:search/results {:query ?query})]) AFTER (query [_] '[{(:search/results {:query ?query}) [:Id]}])

Oliver George08:11:34

I think that's a reasonable query for a remote which expects a pull query.

artemyarulin11:11:12

I have a tree of components and only the last leaf have a query and need some state. Should all of it’s parents request a query as well or can it omit it?

jethroksy11:11:31

@artemyarulin I have the same question actually. AFAIK the parent component needs to aggregate the child components queries, but I think it shouldn't have to... Wonder why we're using a UI tree instead of a UI graph, which seems more coherent with Om's core concepts

artemyarulin11:11:16

well, actually it’s not an explanation but statement

artemyarulin11:11:10

Maybe somebody can elaborate on this? From the same tutorial

Beginners often make the mistake:

  (defui Widget
       static om/IQuery
       (query [this] (om/get-query OtherWidget))
       ...)

  because they think \"this component just needs what the child needs\". If that is truly the case, then
  Widget should not have a query at all (the parent should compose it into it's own query). The most common
  location where this happens is at the root, where you my not want any specific data yourself.

artemyarulin11:11:46

I’m a bit confused why this is a “beginner mistake” doesn’t work and what exactly is the right way?

artemyarulin11:11:42

@tony.kay: Maybe you can explain this part?

jethroksy12:11:30

@artemyarulin maybe he means if the components are structured like A->B->C where B is a stateless/query-less component then just using om/get-query on A is sufficient, but I can't seem to think of a use-case... Gotta test this out when I get back

griffio12:11:57

@artemyarulin: I think some of these design issues came up a few days ago - DN - "it will take a while for people to see this but many problems can just be fixed by making up links…" Some links to the discussion - May help! https://clojurians.slack.com/archives/om/p1448317871002468 https://clojurians.slack.com/archives/om/p1448317970002479 https://clojurians.slack.com/archives/om/p1448318514002494

jethroksy13:11:19

@artemyarulin: I think I get what @tony.kay is trying to convey here. He means that if there exists 2 components that share the same data, and only the same data but have a different representation, then yes I agree, its better to give the data an ident and pass that to the two differing views. DN has made it clear in the last link that there is no need to cascade the child query through the root.

jethroksy13:11:39

to be fair the term "tree" is technically correct, but fundamentally confusing when trying to think in graphs...

jannis13:11:38

@jethroksy: I'm not 100% sure but links are still specified in component queries and those can't just hang in the air, they have to be referenced (directly or indireclty) in the root query.

jannis13:11:19

Even in the Thinking With Links! example, the Item query is referenced in the root query: [{:items (om/get-query Item)}]. And you still need to pass the returned items (with the result of your link embedded in them) down to child components.

jannis13:11:41

I'd be surprised if there was a way around this.

jethroksy13:11:29

@jannis I understand that child queries must compose to the root, but if an interstitial component between the child component and the root component does not require the data, then it should not (and does not) require an om/get-query for the composition to be done. Would I be correct in saying that?

jannis13:11:37

Right, that's been the case all along. If you have Root -> List -> [Item] as components, List often doesn't need its own query.

jethroksy13:11:38

all in all anything specified in queries has to somehow end up in the query in the root component

jannis13:11:49

Yep, that's correct

jethroksy13:11:13

that was @artemyarulin 's question simple_smile

jannis14:11:41

Ok. Somehow I interpreted the discussion as being more about links than about chaining queries up to the root. Nevermind simple_smile

jethroksy14:11:00

@jannis thanks anyways!

jethroksy14:11:28

Also, I get the same problem as @olivergeorge with the Remote Synchronization Tutorial with :onKeyUp, can't type anything into the input box unless i change it to the other recommended :onInput, can anyone else confirm?

griffio14:11:39

@jethroksy: Hi, works for me with Safari and Chrome - e,g if I type in “Clojure" (over two characters). With :onKeyUp that is.

jethroksy14:11:12

@griffio: that's odd, doesn't work for me on mozilla and chrome. It's alright then!

griffio14:11:05

@jethroksy: And works for me in the Fox. I don’t think onKeyUp is an actual problem - it doesn’t work for all input types like spinners etc. Also check you are running a clean alpha24 and not master? My version is here : https://github.com/griffio/om-next-tutorial all the tutorials.

jethroksy14:11:09

@griffio: cloned your repo and it works. I'll figure the actual problem a week later, gotta head back to my army camp xD

griffio14:11:00

@jethroksy: OK - good luck!

artemyarulin15:11:24

@jethroksy: @griffio Thanks a lot, I understood it finally simple_smile

griffio15:11:28

Hey good stuff! 🚀

griffio15:11:33

OK - I think that the problem in the Remote-Synchronization-Tutorial that some were seeing with auto suggest is the input value is being set to "" each time! So pressing any key will always yield “” when using :onKeyUp -> however using :onInput instead works. https://github.com/omcljs/om/wiki/Remote-Synchronization-Tutorial In this version it is "nil" as the key doesn't exist. https://github.com/omcljs/om/blob/master/src/devcards/om/devcards/autocomplete.cljs#L65 I don't think we even need the "query" passed in for this to work. (defn search-field [ac] (dom/input #js {:key "search-field" :onKeyUp (fn [e] (om/set-query! ac {:params {:query (.. e -target -value)}}))}))

griffio16:11:14

Well, It Works On My Machine (tm)

tony.kay16:11:24

@jethroksy: @artemyarulin Yes, what @jannis said about Root->List->Item is what I'm talking about. Specifically, the beginner mistake is to use another component's query as the query of a parent. E.g. (query [this] (om/get-query Child)). If you want to make the parent stateful, then it has to have it's own query (e.g. the child query has to be in a join): (query [this] [{:child (om/get-query Child)}]), but then all you're doing is creating work for yourself in writing a query, teasing apart props, just to pass data through a component that wasn't interested to begin with. The only reason to do that is if the parent in this example was meant to be a black-box reusable component (so that it's parent would not know about the child's query).

tony.kay16:11:00

@dnolen: on graph loops: When I left refs in place the tests pass, but when I tried it out in my app something when awry in server interaction at normalize*. It was late and I figured "well, as long as it is consistent, graph loops with recursive queries are probably a non-happy path of code, and as long as we do something sane it is probably ok" simple_smile

artemyarulin16:11:00

Hm, I thought the whole idea is to make all the components reusable as possible == kinda black box by default

artemyarulin16:11:34

but thanks for the explanation @tony.kay, now it’s much more clear for me. Thanks again for such awesome totorial!

tony.kay16:11:39

depends on your level of abstraction...you can do what you want. Some components will simply be parts of some larger whole, and won't stand on their own.

dnolen17:11:23

@tony.kay: ok, yeah I think we should separate out why it might not for your app at the moment

dnolen17:11:31

and what we want the consistent behavior to be

tony.kay17:11:35

@artemyarulin: sometimes it's just a function simple_smile

dnolen17:11:57

my current spidey-feeling says just copy datomic, and that means put an ident there

dnolen17:11:09

it’s already the case that this can happen with the link feature

dnolen17:11:21

if you don’t provide a query expression we’re not going to follow links

dnolen17:11:00

that is [:db/id 0] is implicitly {[:db/id 0] [*]}

dnolen17:11:24

and since we don’t have any notion of schema, db.isComponent is always implicitly false

tony.kay17:11:16

could you re-read that...I'm feeling like there is a typo. do you mean "is not implicitly"?

dnolen17:11:30

it is implicitly false

tony.kay17:11:48

other implicit

dnolen17:11:57

we never process the data provided by a link without a schema to guide us

dnolen17:11:01

the schema is implicit in the query

dnolen17:11:36

[:db/id 0] is implicitly {[:db/id 0] [*]}

dnolen17:11:47

this is not a typo

tony.kay17:11:12

yeah, I agree....I guess the prior sentence combined with that still don't compute for me

tony.kay17:11:51

you mean "go deeper"...the link is just "whatever we find"...not a subquery

dnolen17:11:58

that’s right

tony.kay17:11:16

I thought you meant we were not going to process the link...but that made no sense

dnolen17:11:31

yeah sorry, didn’t to mean to imply that

dnolen17:11:42

just that we weren’t going deeper than whatever the link is without more help from user

dnolen17:11:10

but since this is the current semantic (and it’s driven by user choices)

dnolen17:11:18

I think recursion should work the same way

tony.kay17:11:12

OK, so a loop of A->B->A->B->... should end up A->B->[ident A]. I think the way the code is currently structured we'll end up with A->B->A->[idnt B].

dnolen17:11:37

yeah prefer the former

dnolen17:11:47

A->B->[ident A]

tony.kay17:11:55

ok. me too. I just could not remember which way I've seen Datomic do it...I seem to remember being surprised

tony.kay17:11:14

and didn't want to go to extra work to fix something that was right simple_smile

tony.kay17:11:44

I'll bring up Datomic and try it for my own edification

dnolen17:11:50

cool, but I think no need to match Datomic here

tony.kay17:11:25

I'll put idents back in and see where it breaks

dnolen17:11:30

cool, thanks!

tony.kay17:11:01

@dnolen: one more thing...on tracking the loops. What are your thoughts on tracking the path with a set vs the map method I'm currently doing?

dnolen17:11:59

a set makes more sense to me, what was the map buying you?

tony.kay17:11:46

a join to the same ident in a different part of the query on a different keyword

tony.kay17:11:59

rare, but I think possible

tony.kay17:11:04

e.g. crossing the same node that has two outgoing refs

tony.kay17:11:24

:person/mate + :person/friends

tony.kay17:11:05

The set would track the two recursive queries as being the same...but I think perhaps the alg recursion might take care of that.

tony.kay17:11:24

the two paths would be different recursive evaluations, with different tracking sets...well, unless you asked for all of the mates of all of your friends.

dnolen17:11:38

yeah I’m ok with using the map to differentiate

tony.kay17:11:50

I'm not convinced the map even solves it simple_smile

tony.kay17:11:53

but it helps

Tim18:11:30

what is the difference between data and opts?

boz18:11:53

Is it possible to query into a matrix? for example, if I have a matrix like this...

[[1 2]
 [3 4]]
Can I make a component for each cell, which updates only when it's cell changes? So, e.g., only the '2' -> '22' causes that cell's component to update if the matrix changes to this...
[[1 22]
 [3 4]]

dnolen18:11:23

@boz it’s possible but you will need spend some time with Om Next before it will be obvious how to make that work

dnolen18:11:54

@tmtwd: data opts is Om Now stuff. If you’re starting with Om I recommend just jumping into Om Next.

Tim18:11:08

fair enough

dnolen18:11:11

but basically data is like React props, and opts is like once only initialization

dnolen18:11:25

there is no React analog for opts

boz18:11:29

is the datomic pull syntax the place to study how to get the matrix thing to work?

dnolen18:11:21

@boz not reallly, I can’t recommend anything other than going through all of the tutorials

tyler18:11:27

Does anyone have any examples of the "state delta" from the merge! doctring? I’m experimenting with remote transactions and I’m having difficulty trying to figure out what the default behavior is supposed to be.

sander19:11:51

is this a bug? when i add a :current-user mutation to the Thinking with Links! example, the change is only rendered in one of the items. code: https://gist.github.com/sander/97c50192c24d686a1e3d

dnolen19:11:50

the only way that re-renders happen is if you specify the keys that need to be re-read

boz19:11:40

@dnolen: OK. I have been through the tutorials and have something working but the whole matrix and every cell gets re-rendered as far as I can tell. So I expect I’m doing something wrong. … I’ll work on it some more and ask again when I can be more clear. Thanks again

sander19:11:46

@dnolen: still getting the same behavior when the mutate-fn returns :value {:keys [:items]} instead of :value {:keys [:current-user]}, should i specify a different key?

sander19:11:29

(updated the gist)

dnolen19:11:33

@sander I think you do not understand what the tutorials and documentation describes

dnolen19:11:41

:value doesn’t do anything at all

dnolen19:11:50

you have to specify the keys to re-read in transactions

dnolen19:11:12

like in the transaction query expression itself

sander19:11:22

@dnolen I see, still I don't get it... the query expression is '[(change-email)], right? should I add something there to influence re-rendering?

sander19:11:35

it seems that re-rendering only happens in the subtree from which I query the mutation. so one solution is to query the mutation from within SomeList and not Item

sander19:11:54

I wonder if that’s the only good solution in om.next. it seems to match what I understand of React (data down, events up in the tree)

dnolen20:11:52

'[(change-email) :items]

dnolen20:11:57

that’s the transaction you should be running

sander20:11:10

thanks, works indeed! so if I understand it well now, om.next/transact! takes "a query expression that includes mutation" (docs), and any other queries that I want executed; the read queries will translate to (new) props passed to the root component

dnolen20:11:42

the only part that is true is

dnolen20:11:52

“and any other queries I want executed"

dnolen20:11:58

the later stuff is not true

dnolen20:11:55

due to path optimization and other things the root component may or may not be involved at all

sander20:11:28

ah right, so it is really only for triggering re-rendering (in an optimized way)

sander20:11:43

just opened up the next.cljs source code, the transact! doc appears actually very clear on this

sander20:11:21

thanks for your help! think I understand it now up to a level I can work with it simple_smile

dnolen20:11:29

right but to be clear nothing to do with optimization

dnolen20:11:45

that’s entirely up to you how much of your UI is affected

dnolen20:11:03

so whether you get a root re-render or something more precise - that’s in your control

sander20:11:37

I assume the re-render only happens in components (+ children) that have a query reading from the specified keys, and get changed props because of that

sander20:11:10

but I'll await the path optimization tutorial before saying more possibly false things, don't need to understand how it works right now simple_smile

Oliver George20:11:07

@dnolen: I'd be interested if my comment above modifying the autocomplete query looks like a rerender logic bug.

dnolen20:11:15

@olivergeorge: you query doesn't make sense refer to the grammar

Oliver George20:11:28

Okay. Will do.

Oliver George20:11:20

Hmm, I can't see how I would say "search wikipedia for 'David' and return url and title of each result.

Oliver George20:11:23

I guess I expected something like datomic's pull spec limit example. '[{(limit :track/_artists 10) [:track/name]}]'

dnolen21:11:14

The grammar shows you how to write that

dnolen21:11:33

Your last example doesn't follow the grammar

Oliver George21:11:52

Okay thanks David I'll look more closely

dnolen21:11:31

Basically paramerization is always the last thing

tony.kay21:11:39

@dnolen: if you have a min, I'm trying to fix what looks like a problem in normalize*, but it is a lot to comprehend. I have debug output, so I know where it is going wrong, I just want to ensure i'm not breaking something.

tony.kay22:11:45

actually not in normalize*. Looks like the tempid remap set all of the refs to nil for some reason...

tony.kay22:11:23

I'll look into it some more...

tony.kay22:11:07

@dnolen: nvm. I found it

Oliver George22:11:52

Okay, worked it out from grammar/hints. Thanks. Corrected query would be something like this (query [_] '[({:search/results [:url :title]} {:query ?query})])

anmonteiro22:11:32

@jannis, @tony.kay so from today's earlier discussion in the channel, I'm left with one doubt: after all queries don't have to compose to the root? or do they? I might have been wrong all along..

tony.kay22:11:12

@anmonteiro: The queries in the UI have to compose to root.

tony.kay22:11:05

with path optimization, you can supply a mechanism whereby the whole query does not have to run run from root, but instead can run from a component with an Ident....but again, you supply the mechanism (in the form of read functions that can tolerate starting from that ident (or return nil if they cannot, in which case the query will run from root)).

anmonteiro22:11:01

so if I have, as discussed, components A->B->C, and only C needs [:foo], does A have to declare in its query something like [{:c-query (om/get-query C)}] ?

dnolen22:11:12

Not necessarily, B might do that

anmonteiro22:11:33

then if A is root, it doesn't need to declare it?

anmonteiro22:11:02

in that case, the query won't really compose to root, or will it?

dnolen22:11:29

Because A needs B query

anmonteiro22:11:23

right, in that case yes

anmonteiro22:11:25

that I understand

anmonteiro22:11:51

but if B is stateless and declares no queries, A must declare it. Correct?

anmonteiro22:11:59

I feel like this has been a lingering question for me; and I've seen others with the same doubt. Maybe something worth adding to the wiki FAQ. I'll probably write something on this, but that'll probably need some reviewing in the channel

dnolen23:11:21

Yes A must have all the queries but how you split it up and who is responsible is up to you