Fork me on GitHub
#om
<
2015-12-14
>
anisoptera02:12:00

has anyone gotten a list view working in om next with react native on ios?

anisoptera02:12:12

maybe i’m just not applying the right styles

a.espolov02:12:02

Guys how send params to om.parser remote read fn on backend?

roelof06:12:46

Can I mixed selmer with om / om-next for templating

dvcrn07:12:32

did {:remote true} change by chance?

jannis09:12:57

@dvcrn: Nope, still works in alpha28.

jannis09:12:18

@a.espolov: Use parameterized queries and Om will automatically pass them to both client and server-side read via the third argument.

roelof13:12:56

No one who can answer my question ?

dnolen13:12:22

@roelof: it’s likely that few people know anything about selmer

roelof13:12:49

@dnolen: oke, so selmer is not used often by clojure people which do web development ?

jetmind13:12:17

@roelof I think you should be able to render selmer template and then mount om app on one of the DOM elements. If you want to write your om components markup in selmer I don't see how it's possible. I didn't use selmer myself, though.

dnolen13:12:57

@roelof: it’s not one of the more popular options far as I can tell

dnolen14:12:33

as @jetmind said if it’s a templating thing then the story is really the same as any templating thing that isn’t React or React-like

dnolen14:12:42

you can’t really share templating logic

roelof14:12:53

oke, I think the most popular is hiccup but I do not like the way I have to make template inheritance work

roelof14:12:36

Im looking for a nice one which I can use for a ecommerce shop. so a lot of html code is used on every page. And I think the whole project will be 10 - 20 pages

jetmind14:12:51

@roelof: you can use Selmer to render static part of your page on the server and then use Om only for dynamic bits. If you want to write a SPA using Om only, I guess you're limited to om's templating or sablono (hiccup-style react dom wrapper)

roelof14:12:33

Thanks, That is what I had in mind . I do not want to write a SPA . I do not think a ecommerce site is handy with SPA and I have no expercience with building SPA.

roelof14:12:08

Next stop. Trying to find some tutorials or books to learn Om / Om-next

roelof14:12:25

is this a good one for a absolute beginner : https://github.com/omcljs/om/wiki/Quick-Start-(om.next) ?

dnolen14:12:39

@roelof: it depends on what you mean by absolute beginner?

dnolen14:12:03

if you’re new to Clojure(Script), React, Om - then you will have a pretty steep learning curve

roelof14:12:53

Im a beginner with I think one month experience. Im new to React and Om . Never learned that

roelof14:12:09

So first learn React then ?

dnolen14:12:07

@roelof: you definitely want to examine React, you may also find that Reagent is a better stepping stone if you’re coming to grips with Clojure(Script) at the same time

roelof14:12:47

I know , but on Reagent I have to use Hiccup and I find it not handy with the project I have on my mind

dnolen14:12:30

I don’t follow Reagent closely so I don't know if the templating is pluggable or not

roelof14:12:54

but thanks

roelof14:12:19

The Reagent people say only hiccup can be used

roelof14:12:28

again thanks for the time

dnolen14:12:10

@anmonteiro: yes that's fine

anmonteiro14:12:52

does it bother you that there would be duplicated code?

anmonteiro14:12:04

not sure about creating a .cljc file with only dispatch, but that might be cleaner

dnolen15:12:27

@anmonteiro: it does not bother me for something this trivial

dnolen15:12:40

at some point will need to better sort what is shared

dnolen15:12:49

but for the time being OK with a quick fix

tony.kay17:12:48

@dnolen: When doing a remote interaction, the remote parse is going to return a query. I'm trying to avoid a race condition. When is it appropriate to mark in the app state that you are going to fetch something? It is a pain in send, because you might need to mark several things "in progress" based on the query...but the remote parse code is supposed to be side-effect free. The race condition comes in when someone interacts with the UI while the query is in progress....you don't want the remote parse to see "not present" again, but instead "loading".

dnolen17:12:24

I think marker values in app state are always fine

tony.kay17:12:44

right, but when is it appropriate to update the marker?

tony.kay17:12:02

local read via action thunk is too early

dnolen17:12:26

you’re allowed to interact directly with the app state for a reason

dnolen17:12:33

and outside of anything in the API

tony.kay17:12:27

the easiest place is during the remote read phase, so OK to swap a marker during that?

tony.kay17:12:13

It is idempotent, but not side-effect free

tony.kay17:12:17

I see no problem, but this seems like a formalism that needs to go in the "cookbook"

a.espolov17:12:43

@jannis: "parameterized queries and Om" static om/IQuery (query [this] '[(:animals/list {:start ?start :end ?end})]) this it's ok example for remote read om.parser?

jannis17:12:57

@a.espolov: Absolutely. The signature of the parser :read function is [env key params], so on both client and server side params will be {:start <val> :end <val>} in this case.

a.espolov17:12:40

params on server read method is nil

dnolen17:12:00

@tony.kay: I wouldn’t go so far as to write anything down as pattern here

dnolen17:12:07

not without a lot more consideration

jannis17:12:47

@a.espolov: Are you sure the query is sent to the server and parsed from the HTTP/WS request there correctly?

a.espolov17:12:11

yes, if commented key utilizing params then server get good response

jannis17:12:08

@a.espolov: That's odd. Can you post your query, your client's read function, the send function, the server read function and the output of (clojure.pprint/pprint env) + (println key) + (println params) on the server side in a gist?

jannis18:12:37

@a.espolov: What does your query look like exactly? It's not '[(:animals/list {:start ?start :end ?end})] for sure 😉

a.espolov18:12:59

I have not one thing is clear whether you can use a nested structure QueryParams?    static om / IQueryParams    (params [this]            {: xyz {:sort-key :abc :sort-type :desc })?

jannis18:12:38

Sure, it's just a map, should work.

jannis18:12:09

But I need to see the query to be able to tell whether it's correctly parameterizing.

jannis18:12:43

How about the contents of (query [this] ...)?

jannis18:12:03

Please don't make me parse transit in my head 😉

a.espolov18:12:03

i’m updated gist

jannis18:12:30

Ok, this is what's wrong:

a.espolov18:12:01

request params is'ok

jannis18:12:06

You write :inspection.list/outlet {... param map...} where it should be (:inspection.list/outlet {... param map...})

jannis18:12:30

Parameterization works via the (<query> <params>) notation.

jannis18:12:33

Not without.

jannis18:12:01

The way you're doing it is that :inspection.list/outlet and the param map are treated as two separate sub-queries. Even worse, maps in queries are considered joins, so Om thinks the params are a query for the keys :paging, :filters etc.

jannis18:12:11

If this is unclear, read up on the query syntax on https://github.com/omcljs/om/blob/master/src/main/om/next/impl/parser.cljc#L5 and look at the documentation in the wiki. https://github.com/awkay/om-tutorial might also help.

anmonteiro18:12:19

I'm having a little trouble with Union queries

anmonteiro18:12:57

my query is of the type [:foo {:bar [:some/key] :baz [:other/key]}]

anmonteiro18:12:27

though it seems Om is treating the union as a join, and only parsing the :bar part

anmonteiro18:12:09

looking for some pointers on what /where to look for

jannis18:12:59

@anmonteiro: Hmmm... I might be wrong but the syntax for unions and joins is ambiguous, at least according to the parser docs. So not sure.

anmonteiro18:12:04

I've checked the grammar

anmonteiro18:12:23

it looks that my query matches it

anmonteiro18:12:27

at least I believe so 😛

jannis18:12:19

For it to be detected as a union I mean.

jannis18:12:20

But no, that doesn't make sense.

anmonteiro18:12:53

you're right

anmonteiro18:12:55

seems like a bug

anmonteiro18:12:03

because it doesn't make sense

jannis18:12:04

I think it should be a join when there is just one key/value pair and a union when there's more?

anmonteiro18:12:38

does my query look wrong according to the grammar?

jannis18:12:30

Nope, it's fine

wilkerlucio18:12:32

doesn't it depends on the "level" that you are? for example, at root it's union, at property level is a join

anmonteiro18:12:30

would appreciate @dnolen 's input

wilkerlucio18:12:33

@anmonteiro: wouldn't you have to put an name before adding your union? like: [:foo {:name {:bar [:some/key] :baz [:other/key]}}]

anmonteiro18:12:58

@wilkerlucio: yes according to the code, no according to the grammar

anmonteiro18:12:04

or at least it seems so

jannis18:12:12

Yeah, I think so too. The root of the query is a vector of query expressions, and those can be keywords, idents, param expressions, joins and unions. And both joins and unions can be EdnMap(Keyword, QueryRoot).

wilkerlucio18:12:32

maybe the grammar should change to accept unions only at root and join levels?

jannis18:12:33

Unless... unions have to be at the root of a component query and that's just not part of the grammar.

anmonteiro18:12:41

not sure if it's a docs problem or a bug, I can understand if it needs to be as @wilkerlucio says

anmonteiro18:12:18

unions can definitely be at the root level

anmonteiro18:12:45

in DashboardItem's query

wilkerlucio18:12:31

there it adds a name for it, this is the kind that I mean for "join level"

jannis18:12:51

Yeah, in that example it's not the root query, it's a subquery that's joined into the root query.

anmonteiro18:12:18

right, but it's at the root of DashboardItem`

anmonteiro18:12:25

it's what I meant

jannis18:12:32

I don't understand the parser code well enough, so I can only guess. @dnolen to the rescue? 😉

anmonteiro18:12:52

I haven't read through it too

wilkerlucio18:12:06

@anmonteiro: on your example, [:foo {:bar [:some/key] :baz [:other/key]}] I can't see how you would get he value of your union, which name it would have on the return?

wilkerlucio18:12:36

it looks more like two joins instead of an union, is that correct?

anmonteiro18:12:41

I was going to have parse keys for :bar and :baz

anmonteiro18:12:59

@wilkerlucio: it looks that you might be right

anmonteiro18:12:24

so the docs might need to reflect it, but we'll only be sure when David gets summoned 😉

wilkerlucio18:12:48

he eventually will simple_smile

dnolen19:12:46

unions do not stand by themselves

dnolen19:12:50

they need to be a part of join

anmonteiro19:12:19

that clears things up

dnolen19:12:10

fixed the grammar

anmonteiro20:12:41

so I've been writing some routing experiments

anmonteiro20:12:39

and at this point I believe that using unions to perform routing in an app that does some form of remoting might not be ideal

anmonteiro20:12:20

because the parser will always attempt to read every key present in the union query

anmonteiro20:12:55

so either 1) we incur in a lot of remote requests everytime we re-render (will read every key of every route) 2) we have to write a lot of unnecessary code to prevent 1)

anmonteiro20:12:17

the approach that's suiting me best atm is using set-query! to the current route's component query

anmonteiro20:12:40

would love to hear people's opinions on this

noonian20:12:52

You can prevent the extra requests by only getting the remote query for one sub-branch of the union in the read for the union, but it does take more code. I like using a union so you can see the entire demand (unioned across pages) in a single query. Currently though, you have to write a lot of custom code to re-rwrite your queries in your send function if you don’t want your server to know about your routing machinery. I’ve talked with @tony.kay a bit about this; currently process-roots doesn’t traverse union queries but if it did it would go a ways to help solve this issue imo. I’ve personally been trying to avoid using set-query!, but thats how I initially tried to tackle this problem. When using set-query! I had to write extra code to construct a query that could be used to normalize data across my app since at any given time the root query might only have enough information to normalize the data for the current page.

tony.kay20:12:56

I'm doing routing by set-query, and am not using unions in routing

tony.kay20:12:16

It is perfectly legal to switch out a join via a query param from IQueryParams (e.g. compose in a different components query via set-query). So, instead of stating "it could be one of these, detect it via state", I just end up with "it is exactly this" in the query, which works nicely with process roots.

noonian20:12:39

I guess what I don’t like about it is that it forces me to move state out of my state atom and into the component instance whose query is changing

anmonteiro20:12:22

@tony.kay: exactly how I'm tackling the issue

tony.kay20:12:29

@noonian: I abstracted that into helper functions. The component can call set-query and pass something generated from helpers.

jannis20:12:40

I've taken a slightly different approach to routing recently: Use bidi to translate from URLs to mutations (when loading a page) and from app state to URLs (e.g. when selecting something). Almost all routing stays out of Om and Om simply has an app state that it renders.

dnolen20:12:21

these all sounds like plausible approaches

dnolen20:12:40

another way that I haven’t time to think through

jannis20:12:58

https://github.com/Jannis/custard/blob/master/src/web/routing.cljs (`navigate-to` is called whenever the page is loaded or the URL changes, activate-route is called by my App component to change the URL and trigger the necessary mutations to get to the desired state): https://github.com/Jannis/custard/blob/master/src/web/app.cljs

dnolen20:12:09

given a route description use the anonymous ui macro to generate the needed route classes with union query bits

noonian20:12:34

@jannis: I do a similar thing, do you just use a static query for the entire application then? what about remote reads?

jannis20:12:42

bidi could be a bit simpler but I quite like the combination.

noonian20:12:03

Yeah, I’ve been using bidi so that I can use the routes in the server to render the index for exactly the routes that the client needs.

jannis20:12:48

@noonian: Nope, parameterized. That app there serves versioned data from Git, so the query is parameterized by commit, more or less. Remote reads are done on page load and the rest is done via sente push notifications from server to client (e.g. when there's a new commit or working directory changes) that then trigger refetching the current "commit" remotely. And it reads remotely whenever you change the "commit" (or branch or tag) you're viewing. It doesn't do lazy querying for views/routes.

anmonteiro20:12:42

the ui approach David mentioned seems like something to try

anmonteiro20:12:56

not sure I understood it entirely though

noonian20:12:12

I like the anonymous ui approach. I think its basically an iteration of the union approach though, so will need to solve the problems with remotes for unions before going down that route I think.

anmonteiro20:12:38

@dnolen: whenever you have time I'd love to hear some more details

r0man21:12:09

@noonian, @tony.kay When using unions for routing, is it possible to change the union dynamically at runtime (via set-query!)? I think of all the code behind those routes as possible candidates to put into a Google Closure module to optimize the build. I'm worried that when referencing components from those routes, the code motion gets prevented and a lot of code lands in the base module instead of the route module.

noonian21:12:41

@r0man: I haven’t done anything using code motion. But I think if you write the parsing code to just use the provided union query it encounters, and figure out what to union on by some function of the app state, then you won’t need to statically reference the actual components used to build the query and could probably use it in conjunction with set-query!.

noonian21:12:45

But you will run into the same problems of building the correct query to use when trying to normalize data I think.

jannis21:12:31

@dnolen: I'm guessing there is no way to pause the queue processing in the reconciler?

jannis21:12:25

When you use sente to communicate with the backend. It may not be ready right away though, so you have to queue pending queries in :send, using a channel perhaps. Or the reconciler could provide a way to prevent queues from being processed until a condition is true?

dnolen21:12:43

@r0man: code motion is a nice thing but it’s very conservative

dnolen21:12:01

in general you do have to be explicit when you want something to go into some specific module

jannis21:12:06

This probably isn't limited to sente. Any backend that you have to wait for to become available for comms.

dnolen21:12:41

@jannis I do not follow

dnolen21:12:50

put your async logic in send using whatever makes sense

r0man21:12:49

@noonian, @dnolen: I played a bit around with code motion and sometimes I ended up with empty files when not beeing careful. Like referencing symbols from those route modules. I'm using om/add-root! at the moment to swap components out at route changes. Not sure exactly if this is a good solution or not 😕

anmonteiro21:12:27

@r0man: that was my first approach to routing

anmonteiro21:12:49

it's how we did things in Om (Now) world, so I firstly tried that way

anmonteiro21:12:03

it might represent a problem with normalization

noonian21:12:10

Have you noticed much of an improvement in code size when it works? I kind of assumed most of the code supporting my app was cljs, om, and react.

anmonteiro21:12:43

switching root when the route changes is definitely a simple approach

anmonteiro21:12:00

it didn't play out for me because I ended up having to repeat a lot of code

r0man21:12:50

@noonian: when code motion worked I had a JS file for each route. I have 10 modules each between 5k and 21k of size. There isn't much code yet for each route yet, but I think it adds up. I think not having to load all view code on the initial app load is desireable.

noonian21:12:23

Thanks for sharing that data

monjohn22:12:39

I am struggling a bit with merging the data returned from remote. It is in the form: {:list [{:a 1}]} which matches a top-levle key. Do I need to define a ‘merge-tree’ function to merge it into the local state?

jetmind22:12:52

@monjohn: depends on what you're trying to do. If you want to replace all the local data for :list key with what server returns, you can use default merge-tree, which is just plain merge of top level keys. If you need to do some smarter merge, you should supply your own implementation of merge-tree

monjohn22:12:56

@jetmind: Got it. Thanks.

chris-andrews23:12:37

I noticed that I can call (om/params MyComponent), but (om/get-params MyComponent) returns #object[Error Error: Assert failed: (component? c)]. Is om/params something I should not be using?