Fork me on GitHub
#om
<
2016-03-22
>
urbanslug06:03:39

Why should I pass info around through the app-state and not via channel?

arcanumxiii07:03:27

And of course if you change the app-state, and it’s some data needed for an Om request, the relevant update will be done without your involvement

urbanslug07:03:26

I get it, I won’t need to care about the reception of what I put into the channel. Om/react will handle the reloading if and when I update the app-state.

erichmond13:03:15

Hey guys, is Om.Next still considered alpha, and are there any known breaking changes coming down the pipe?

dnolen13:03:59

@erichmond: still considered alpha

dnolen13:03:13

nothing known, but that’s not saying much

erichmond13:03:25

thanks, that’s actually still really helpful. one last question, do you know how long it might be until it hits beta? I just need a rough rough answer in weeks or months or years? I’m asking because we are speccing out projects for 2016, and there’s a project that might be a good fit for Om Next coming in the next few months

erichmond13:03:58

I mean, is it weeks away, months away, or years away *

thiagofm14:03:19

I was thinking... you have to pass down (om/props this) down to the children components in order to access the queries. Isn't there a possibility to make this implicit? And then you could just have an arg to send down computed information

thiagofm14:03:10

Or is it a bad idea per se for some reason? Maybe too much magic? I see this common pattern frequently in what I'm developing

thiagofm14:03:20

Basically 100% of time

danielstockton15:03:20

You don't always want to pass everything to every child

hueyp16:03:27

@thiagofm a children components query can be dependent on the parent — e.g. [:todo/text :todo/completed?] — which todo? Relay / Falcor address this differently than om though — the parents pass a pointer, not data, and the children query the store themselves vs getting it via props (similar to how an om component can get props directly on a reconcile)

thiagofm16:03:01

@hueyp: but in that case wouldn't it look at the computed props?

thiagofm16:03:09

"which todo?"

hueyp16:03:28

[{[todo/by-id 1] (om/get-query Todo)} {[todo/by-id 2] (om/get-query Todo)}] and Todo’s query is [:todo/text :todo/completed?]

hueyp16:03:52

you need the identity information in order to parse the Todo query

thiagofm16:03:36

I see, thanks

thiagofm17:03:25

I wish get-params could get the params of a component(such as om/get-params Component), like (om/get-query Component), but it can only get the params of the scope of the component, like (om/get-params this)

thiagofm17:03:35

Any reason?

thiagofm17:03:56

I see the code, it's completely different from get-query

anmonteiro17:03:48

@thiagofm: why not use (om/params Component)?

thiagofm17:03:30

@anmonteiro: that is perfect, thanks!

thiagofm17:03:33

The reason why I want this, is that I want to update-query in a children component, but there's no way to do that. So I'm writing my own abstraction in order to update the query of a children component from the root component

thiagofm17:03:52

Not sure if I'm going the right way, but I'm getting into something... 😛

anmonteiro18:03:14

I think that sometimes it's worth stepping back and looking if what you want to do really makes sense

thiagofm18:03:10

I want to create something like: (om/set-query-from-children Component key value), so I can just use it from the root

anmonteiro18:03:17

I'm not saying you're doing things wrong, but if you find yourself having to go out of your way to implement abstractions over stuff that should be simple, this might be a red flag

matthavener18:03:01

thiagofm: is this for routing?

thiagofm18:03:37

My problem is the following, I have two components, the root one: Window and the children, called Code. Code displays a file which fetch via a remote in Github, but it's dependable on the :language state, so if the :language is "Ruby", it will fetch ruby code, for example. But I can't modify that query from the children component(set-query inside the Code component)

thiagofm18:03:19

So I wrote something that lets me build the whole query inside the root component, getting it from the children

anmonteiro18:03:23

@thiagofm: you should be able to set-query! inside a component

thiagofm18:03:53

@anmonteiro: in a nested component, I get: Uncaught #error {:message "No queries exist for component path (haxlife.components.window/Window haxlife.components.code/Code)",

anmonteiro18:03:01

@thiagofm: that will happen if your queries are not correctly structured

thiagofm18:03:14

I'll study a bit more then, thanks

cmcfarlen18:03:56

@thiagofm: Can you provide a gist of both components?

thiagofm18:03:26

@cmcfarlen: here you can find the window.cljs and code.cljs https://github.com/thiagofm/haxlife/tree/master/src/cljs/haxlife/components, and there the parser: https://github.com/thiagofm/haxlife/blob/master/src/cljs/haxlife/query.cljs It's kinda outdated from what I have now, but with the queries specified as it is there, I can't set-query! from the code.cljs component

thiagofm18:03:59

I think I can fetch what is the language from the state inside the parser

cmcfarlen18:03:12

@thiagofm: [(first (om/get-query code/Code))] get-query adds metadata to the return value that is used later to determine which component that part of the query is associated with. Calling first will not work for you as it won't have the metadata. You will need to use a join to get Code's query. [{:code (om/get-query code/Code)}]

thiagofm18:03:00

Now it breaks my remote and I can't trace it easily

michaelr18:03:53

what would be a good approach to debug/understand why a view isn't refreshed after a mutation? the write happens, and is followed by a read, and the read data contains the mutation changes - but the view isn't refreshed

thiagofm19:03:58

@cmcfarlen: I have changed it to [{:code (om/get-query code/Code)}], but now it seems that it doesn't send the query params anymore to the read

thiagofm19:03:47

I have at Window: (query [this] [{:code (om/get-query code/Code)}]) and at Code: (query [this] ['(:code {:query ?language})])

cmcfarlen19:03:48

@thiagofm: Yeah, this adds more depth to the query. So now the params will be in the ast of the children. You can recursively call the parser on the ast children or you can dig in there from the first read call for :code. Check out (-> env :ast :children) in your read fn.

anmonteiro19:03:26

@adamkowalski: factory accepts a :validator function that receives the component's props

thiagofm19:03:30

@cmcfarlen: the ast will only contain the query from the current read? (I don't want to get issues with stealing other params)

thiagofm19:03:27

Other than that, 👍

adamkowalski19:03:51

awesome, that is exactly what I needed

cmcfarlen19:03:54

The ast will contain the whole query below the "current" key

adamkowalski19:03:55

@anmonteiro: whats the standard way of giving a user feedback if i don’t like the props

adamkowalski19:03:15

should I log a message, or throw an error, or just let the assert fail?

adamkowalski19:03:44

when the assert fails I get a really vague message by default: Uncaught Error: Assert failed: (validator props)

anmonteiro19:03:32

@adamkowalski: I'd say that the validator is not something to give feedback to users

adamkowalski19:03:49

not end users per se, but more of a sanity check for the developer

adamkowalski19:03:32

i would like to make my components reusable, and be able to share them with others. so if somebody fails to give me all the required props, or passes them in the wrong shape I would like to tell them what happened and how to fix it

anmonteiro19:03:33

yes, that would be the use case

adamkowalski19:03:22

right now I just throw an error that tells you the name of the component and the error message

anmonteiro19:03:25

I think the way React does it is by using invariants

anmonteiro19:03:52

whatever you end up choosing depends on what you want to happen

anmonteiro19:03:12

you can 1) hard error 2) log an error message (e.g. goog.log)

anmonteiro19:03:49

I think the 1st will halt computation after the error is thrown, so that's where you have to choose

adamkowalski19:03:44

ok, and another alternative is to specify pre and post conditions right?

adamkowalski19:03:54

that would be a more clojureish way to specify invariants

adamkowalski19:03:21

so for a websocket component I require at minimum a url, and then for the pre condition I could check if the url is a string

anmonteiro19:03:43

so what would be the function body?

anmonteiro19:03:56

if you're just using pre/post conditions.. simple_smile

adamkowalski19:03:44

(defn- web-socket-prop-validator [{url :url}] {:pre [(string? url)]} true)

adamkowalski19:03:53

i just tried it and it worked great. when it fails it the source maps are good enough that it will point you to the line of code in the cljs file where it failed

adamkowalski19:03:07

otherwise you don’t even notice anything happened

jamescroft20:03:33

Does anyone have any examples of how to model many-to-many relationships in Om next? Eg. Assuming I have Products and Tags, would I store the associated idents on both sides of the relationship or just on one side? Given that in the UI i’d like to display the tags for a product and also the products for a tag.

adamkowalski20:03:55

if you have both products for tags and tags for products it seems like on any change you would need to make updates to both things making your model more complicated

adamkowalski20:03:08

cant you model it with just products having tags associated with them?

adamkowalski20:03:36

then if you want to find which products have a certain tag, just filter through all your products keeping only the ones with the tag you want

adamkowalski20:03:22

you would get the same query ability just with less complexity

jamescroft20:03:03

ok, so thats a vote for only storing links on one side of the relationship. Thanks

thiagofm21:03:19

Let's say I read something from my remote based on a query(for example: language: Ruby), how do I save it to my app state?

thiagofm21:03:39

I don't want to keep querying for the same data, I would like to keep a local cache

anmonteiro21:03:34

@thiagofm: when you call the callback in your send function, the remote data gets merged into your app-state

thiagofm21:03:31

So I would have to merge some part of the query with the remote data, and then posteriorly query the date using the query as some sort of index/key?

anmonteiro21:03:37

I don't understand your question, can you rephrase?

thiagofm21:03:07

Let's say that sometimes I might query for "United States" or "Canada" in wikipedia. I would like to keep a cache of it. In order to do that, following your reasoning regarding the cb. I would have to return in the callback something like {"United States" wikipedia-response}. And whenever I do a read, I would have to verify if "United States" is there, otherwise I call the remote?

thiagofm21:03:10

That should work 😛

anmonteiro21:03:28

yes that should work

adamkowalski21:03:05

@thiagofm: have you heard of optimistic updates?

adamkowalski21:03:51

one thing you could do is when you originally make your transaction, place the data you need into your app state

adamkowalski21:03:17

then send a message to the server. which when it comes back with a reply can make a new transaction to override the data if needed

adamkowalski22:03:45

and for caching do the same thing but in reverse. if the value is already there then don’t ask the server

adamkowalski22:03:03

otherwise send a request and when it comes back transact it into your app state

thiagofm22:03:11

@adamkowalski: luckily in this application I won't have to send data to backend, but this sounds like a good idea!

thiagofm22:03:57

@adamkowalski: yet I don't think this can be used for everything 😞

adamkowalski23:03:19

how do you guys handle om components that don’t need to render anything?

adamkowalski23:03:53

is it fine if I just put (render [_] nil)

adamkowalski23:03:10

it seems like it just generates a no-script tag and wont bother anybody

adamkowalski23:03:04

also I cant make transactions if I dont have a query in the component

adamkowalski23:03:32

so I just did this static om/IQuery (query [this] [])

anmonteiro23:03:16

@adamkowalski: that's an anti-pattern

anmonteiro23:03:32

use om/computed to pass callbacks down the component tree