Fork me on GitHub
#om
<
2015-10-29
>
thosmos00:10:36

@dnolen: Regarding path optimization: I modified @drcode's example to render two child components, one "normal", and one with a nil prop. Both components' (set-state!) trigger reads from the "wrong" parser route, but only one of them actually displays it. https://gist.github.com/thos37/934522181a68ca2f3b72#file-core-cljs-L53-L63

dvcrn01:10:40

@dnolen: I didn't know transit for python exists. Thanks for the tip

mhuebert01:10:24

👍 to computed props & queries from sub-nodes simple_smile

dnolen02:10:24

@thosmos: none of what you said means anything to me yet

teslanick02:10:24

I'm sure this has come up a bunch of times, but what's the Om Next idiom for rendering a child component?

teslanick02:10:52

(dom/div nil ((om/factory ChildComponent))) ?

rburns02:10:37

I think it's normal to define a shortcut to the factory. eg (def my-component (om/factory MyComponent)) and use that to render the component

dvcrn02:10:47

yeah. create the factory once and use that. Otherwise you'll just keep making factories

bones03:10:50

@tony.kay: thanks for your Om Next Overview. Really helpful

sander07:10:29

the IQuery doc mentions “This method should always return a vector.” but in Queries With Unions, DashboardItem returns a map. is that okay because maps can behave like vectors, or doesn’t (query [_]) always need to return a vector?

grav07:10:57

Is it an anti-pattern to use memoization in order to avoid allocating new objects? It’s not that the memoized function in itself is costly, but it will help Om avoid re-rendering the child component.

grav07:10:15

Eg, I memoize (map :foo my-list) which in itself is cheap, but allocates a new object every time it’s called (in render)

grav08:10:00

Nah, forget what I’m saying - lazyness wil save my ass in this case.

grav08:10:03

The reason my child component’s render was called was that I handled an anonymous function to my child component, and (= (fn []) (fn [])) evaluates to false.

dnolen10:10:08

@sander IQuery instances must return valid query expressions - this is always a vector except when you are returning a union expression (which is a map of query expression vectors).

sander10:10:24

@dnolen: clear, thanks

simonb11:10:49

Forgive a silly question: The Om-next quick start says "This component only declares one JavaScript Object method - render." So Object is a protocol? Where is Object as used in Om/ClojureScript defined/documented? I've grepped through the code of Om and ClojureScript looking for "defprotocol Object" but I can't find it anywhere. What am I missing? Thanks.

sander11:10:31

@simonb i think the name Object just refers to the generic javascript Object, and you can declare any method on your instance

simonb11:10:37

@sander Thanks. So Object is not a protocol? The syntax looks like a protocol. But I think you're right. It's saying something like "this is a JS Object's methods" I'm just wondering where the semantics of Object are defined.

sander11:10:57

@simonb: i think this is just the design of the om/defui macro. any function declared under Object will added as a property to the instance (prototype)

sander11:10:13

so read defui's definition if you want to understand how it works

jannis12:10:49

@simonb Yes, all functions after Object become methods of the JS Object. You can define (foo [this ...] ...) in there and e.g. call it from render like this: (.foo this ...).

thheller12:10:53

@simonb: defui is basically deftype and using Object is a way to define instance methods on the type it creates

thheller12:10:09

slight difference to clojure though since defining functions on Object is not possible there

drcode13:10:28

OK, I have now created my first non-trivial Om Next project, will post it on github in the next few of days. I picked something that has a lot of cross-cutting concerns (a generic rectangle packing layout component) and the indirection enabled by the query selector approach made it surprisingly easy to implement (once I understood the design of Om Next well enough, which certainly required some effort)

dnolen13:10:58

@drcode: cool! yes it’s certainly a lot of novelty to sort through simple_smile

dnolen13:10:24

but hopefully once you get past the hump the whole thing just levels off really fast

drcode13:10:50

@nolen: As you say, it's more a matter of novelty, not complexity. The bottom line is that any programmer creating a component first asks themselves "What does this component need to know about?" and the fact that previous-gen client libraries don't have a way of specifying this explicitly within components, via a DSL, adds lots of extra complexity in other libraries.

dnolen13:10:34

@drcode: yep I think as people get used to this model they’ll wonder they ever got anything done before 😉

tord13:10:06

I'm playing with a little toy animation example in Om Next, and have encountered some odd behaviour that I suspect might be a bug. Here's a gist of a simple app that displays a button and a ClojureScript logo, and which makes the logo slide to a random location when the button is pressed:

tord13:10:13

It works. However, if I change the query in the (defui App ...) form to include the animating? key, it no longer works, even if I never use the value of the key anywhere in the component.

tord13:10:12

The code is a bit long, but the first 60 lines or so are not important. All you need to know is that the swap-animated! function uses js/requestAnimationFrame to modify an atom at every frame.

dnolen13:10:50

@tord yeah that example isn't particularly minimal

tord13:10:15

Yes, sorry about that. I haven't found a way to reduce the size. If it's not immediately obvious what is wrong, I can try...

dnolen13:10:19

but can you clarify about the nature of the bug?

dnolen13:10:27

sounds like you don’t see any errors?

tord14:10:05

No, I don't see any errors. But when I include that key in the query, the logo no longer smoothly slides to its new destination, it just jumps there.

dnolen14:10:32

@tord: I would do some more bug isolation

dnolen14:10:37

println etc.

tord14:10:24

OK, thanks. I'll see what i can find, and let you know if the bug seems to be in Om.

dnolen14:10:14

@tord: please do, it could very well be a bug! would be nice to have a basic theory of what’s wrong though.

tord14:10:45

OK, after some println-ing, I now know that the state atom is updated correctly at every animation frame and that the UI component's render method is called at every update, but that the query does not return the updated results. Manually calling the parser inside the render method and printing the results shows the correct values, though.

tord14:10:11

Outline of the relevant parts of the code:

tord14:10:18

The query looks like this:

tord14:10:43

(query [this] [:x :y :animating?])

tord14:10:55

and here is the start of the render method:

tord14:10:02

(render [this]
  (let [{:keys [x y animating?]} (om/props this)]
    (println "rendering App: x: " x " y: " y " animating?: " animating?)
    (println "parser result: " (parser {:state app-state} [:x :y :animating?]))
    ...))

tord14:10:49

The output looks like a long sequence of lines like this:

tord14:10:57

rendering App: x:  0  y:  0  animating?:  true
parser result:  {:x 142.803804, :y 199.72560000000001, :animating? true}
rendering App: x:  0  y:  0  animating?:  true
parser result:  {:x 142.973312768, :y , :animating? true}

tord14:10:26

So the values returned by the queries don't match those obtained by calling the parser manually.

tord14:10:44

I tried printing out (om/props this) for the component, too:

tord14:10:50

rendering App: x:  0  y:  0  animating?:  true
props:  {:x 0, :y 0, :animating? true}
parser result:  {:x 271.592088, :y 289.433904, :animating? true}

tord14:10:11

And the strange thing is that when I remove :animating? from the query, everything works, and the props are always equal to the result of manually calling the parser.

dnolen14:10:38

@tord hrm file an issue with the complete example … I have a hunch what’s going on but I’m curious why changing the query would trigger this.

tord14:10:10

Will do. Trying to simply the example a little first.

dnolen14:10:47

@tord part of the problem I suspect is that the reconciler uses a counter to know quickly whether props are stale

dnolen14:10:01

but you’re not incrementing this from the outside so the old props gets used

dnolen14:10:35

pretty sure that’s the issue, and I’m curious how your example worked in the first place to be honest

tord14:10:04

You mean that the app state should only be mutated directly from the parser, and that mutating it from animation frames messes things up?

dnolen14:10:15

@tord mutating it directly messes things up yes. this can probably be easily fixed.

dnolen14:10:26

anyways post your issue and I’ll try a couple of things.

dnolen14:10:53

banging on the atom from the outside w/o the reconciler being involved is something that should work - so it’s a bug for sure.

tord15:10:28

@dnolen OK, I managed to reproduce the behaviour with a much simpler app. Will file an issue. Thanks for your help!

tony.kay15:10:11

@dnolen: David, I'm updating my overview docs, and I wish to make sure I've got this right: "for *queries*: the parser will only be invoked for either the top-level query, or starting at some node with an Ident". I'm trying to make sure people are not surprised at an entry into the parser at some other point that might jump into a read in an unexpected way. Am i missing anything?

dnolen15:10:39

I wouldn’t write much about parsing yet

dnolen15:10:53

still thinking through the implications of path optimization

dnolen15:10:04

saying too much will mean it will just be wrong when this gets sorted

tony.kay15:10:37

ok, I'll keep it loose.

tony.kay15:10:03

(the prior versions says quite a bit about parsing...but just from a root perspective)

paulb17:10:57

What is the effect of including keys defined by the read multimethod in the query expression of transact!? e.g.

(om/transact! this `[(boards/activate {:ref ~ref}) :boards/active])
the :boards/active part. I got this from @jannis kanban app which I'm finding very helpful to look through simple_smile

jannis17:10:38

@paulb: It tells Om Next to rerender components that query :boards/active after the transaction.

paulb17:10:39

ah ok, thanks

jannis17:10:13

@paulb: Initially, I thought the :value part of what the corresponding mutate function returns would have that effect. Turns out that's only a way of documenting what keys are affected by the transaction. It doesn't have any effect.

paulb17:10:32

yes, I had made the same assumption. imo would be helpful for the Om wiki to include an example of this.

paulb17:10:47

how do you know if it's necessary to provide keys? In the Om wiki examples, components rerender without providing any

jannis17:10:11

@paulb: I've updated the parser documentation: https://github.com/omcljs/om/wiki/Documentation-(om.next)#parser (hope @dnolen is happy with the explanation)

monjohn17:10:21

David said that when transact! is called on a component that component is implicitly included, so (transact! c ‘[(do/it!)]) is actually (transact! c ‘[(do/it!) ~c]) @paulb

jannis17:10:14

I probably shouldn't need to append :boards/active in my demo then. Need to try that.

paulb17:10:30

ah ok the mystery of re-rendering makes much more sense now simple_smile

paulb17:10:58

@jannis I tried removing and everything still works

jannis17:10:17

Updating the code as we speak

tony.kay18:10:19

I just updated my overview docs to fix my mutation misunderstandings. Relevant to the current discussion. Reading the Relay docs cleared up a lot of things. https://github.com/awkay/om/wiki/Om-Next-Overview It is a rough draft, but hopefully it helps people understand the "why" of transact, callbacks, and ":value as documentation on mutation".

tony.kay18:10:08

New intro section covers some conceptual stuff, and the Mutation section was heavily revised

tony.kay18:10:30

I still need to integrate the new "computed" stuff

monjohn18:10:07

@tony.kay: The new introductory material is really good. I know it always helps me to have a motivating case in mind when learning something new. One typo: search for docuemtation

tony.kay23:10:41

@monjohn: Thanks. Typo fixed.

dnolen23:10:43

@tord: fixed your bug, was in fact simple, just needed to move the internal counter into another place.

dnolen23:10:15

@tord as far as I can tell, your animation code never should have worked so I didn’t really look into much further than the fix.