Clojurians
#om
<
2016-01-11
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

rafd01:01:35

if it works then it's probably better; i'm by no means an authority

rafd01:01:52

@sander actually, you can just pass state/reconciler directly without the class->any

rafd01:01:03

(om/set-query! reconciler {...})

adamfrey01:01:49

I’m trying to return tempids from my server after a mutation. When I return {:tempids …} from the :action function it ends up in the :result key like,

{place/create {:keys [:places/list], :result {:tempids …
, but the default om function expects the :tempids key to be one level higher in the map, not nested under :result. How can get my tempid map there when I am calculating those ids in the :action fn?

andrewboltachev01:01:41

@adamfrey: so, do you have control on your server-side code? i.e. responses?

adamfrey01:01:30

I do, the default om parser puts the result of the :action fn into the :result key here: https://github.com/omcljs/om/blob/1a834e750a83e8e25f77f5128374873fb7d22112/src/main/om/next/impl/parser.cljc#L222 I could wrap the parser I guess and pull out the :tempids value myself. I just didn’t know if I was missing a built-in way to do this

adamfrey01:01:19

or if other people already figured this out

andrewboltachev01:01:20

well I don't know the answer then. Might be :result is for server responses

andrewboltachev01:01:29

although parser is in *.cljc file so probably not

cigitia04:01:05

I’m having some trouble understanding how to use Om Next queries in a certain way: Let’s say there’s a Parent component that can instantiate many Child components. A Parent component needs two props, respectively called :bars and :foos, both which are maps containing maps. Each Child component needs two props: one val from :bars and one val from :foos, respectively called :bar and :foo. The single :foo that a Child receives is determined by an :id value inside of its single :bar. How could I express Child’s and Parent’s queries?

nxqd04:01:58

@cigitia: you can try like this {:bars :foos} from parent

nxqd04:01:09

then you pass down the props to child

nxqd04:01:38

(child {:bar (get-from-bars bars) :foo (get-from-foo)}

cigitia04:01:23

What should IQuery’s query method return for Child, though?

cigitia04:01:49

Neither a key called :bar nor one called :foo could be understandable to the root parser, as far as I can tell; there’s no way to implement the root parser that I can see to process those keys if you request them.

cigitia04:01:12

The parser can only know about a map of maps called :bars and a map of maps called :foos.

cigitia04:01:20

It can’t know what particular :foo and :bar a Child needs…unless we would be supposed to use query parameters here?

nxqd04:01:16

hmm, I'm no omnext expert but I would try my best here. actually I'm not sure about the case you want to write query, but if you just pass props like the one I show you above, and get it from child render like so {:keys [foo bar]} (om/props this) it would be fine

nxqd04:01:05

the other way is to specify the query on IQuery of Child and write a custom read function to return correct [:foo :bar] from foos and bars. I'm not sure about this one, others might help you with this.

cigitia05:01:56

@nxqd: Thanks for the help. One problem is that, from what I understand, queries built from IQuery are completely separate from the rendering process; they’re statically built from each other so that—ohhhhhhhh. I think I got it.

cigitia05:01:25

Maybe child components’ query functions can return anything they want, as long as their results are understood by the parent’s query function.

cigitia05:01:06

And so then the parent could take its child components’ (static!) queries and return something completely different—as long as that result is in turn understood by its own parent component’s query function (or the root parser).

cigitia05:01:08

…I think.

cigitia05:01:21

Thanks for the help again; I’ll see if this works.

nxqd08:01:37

@anmonteiro: I think there is bug in history cljs in your aemette template, when I click back it doesn't work.

rafd08:01:59

@cigitia child components that require two different things should be composed of components that each describe just a single thing (even if those components are JUST the query)

danielstockton08:01:59

can anyone point me to an example of the current best routing practices in om next?

nxqd08:01:06

@danielstockton: check this template https://github.com/anmonteiro/aemette

rafd08:01:52

my understanding is that david is waiting to see if om.next needs to be changed to better support routing

danielstockton08:01:20

@rafd this is also my understanding, i was asking in case there was already a best practice

rafd08:01:33

@danielstockton: nothing definitive, various approaches still

anmonteiro11:01:55

@nxqd: looking into it

hugobessaa12:01:47

is there a pattern to more easily test cursor transactions on om.core?

hugobessaa12:01:34

I have many fns that transact the state and I'm not being able to simply assert my app-state without rendering to dom and testing component output

danielstockton12:01:03

why do you want to test cursor transactions? i'd say that's the job of om's test suite, you can concentrate on testing your application

danielstockton12:01:50

instead of rendering to the dom, you can render to a string and assert on that (maybe?)

nano13:01:48

@anmonteiro: Looking at your lein template wrt routing, any idea how to handle queryparams on your navigation-points that result in :send calls?

nano13:01:21

@anmonteiro: I see :navigation-data, but it doesn't seem to connect as params to the child query anywhere.

nxqd13:01:54

hi guys, is there any good function to test remote fetching in om next ? I have specifed {:remote true} in :value but it doesn't seem to make any request.

danielstockton13:01:55

@nxqd Did you add a :send function on the reconciler?

nxqd13:01:27

yes, I have the send function.

nxqd13:01:45

actually, I made it worked before in my prototype app, but now some how it doesn't work ...

danielstockton13:01:14

so send fn isn't called?

nxqd13:01:04

good point, let me check

nxqd13:01:28

thanks -_-

nxqd13:01:42

actually it has bug in that function, I haven't imported xhrio

nxqd14:01:24

btw, is there any good way to prevent this kind of bug. Since if I use figwheel, it only shows the error in a namespace only when I change something in that namespace.

danielstockton14:01:19

not sure, i'd say just by separating concerns as much as possible to make it easy to track down the source of any problems

danielstockton14:01:27

usually my errors appear in the namespace im working on

a.espolov14:01:55

In the backend there are parser method (defmethod ' inspection mutatef-target/review) On frontede in pareser method (defmethod mutate ' inspection-target/review) is remote truebuddi (om/transact! this `[(inspection-target/review ~other-map)]) App send request to server, server send response not found method What am I doing wrong?

nxqd14:01:24

if you see there is a request to backend then your frontend does good job

nxqd14:01:33

then the problem would be on your backend instead

a.espolov14:01:10

yes, backend not found mutate fn

a.espolov14:01:23

for inspection-target/review

a.espolov14:01:00

inspection-target/review loyal notation for defmethod?

danielstockton14:01:35

front and backend parsers deliberately share the same notation, only difference is the env you pass to backend (instead of state)

adamfrey14:01:18

now there’s more of audience in the channel, does anyone have any thoughts on my tempid question from last night: https://clojurians.slack.com/archives/om/p1452476269010231

danielstockton14:01:00

this is one approach

adamfrey14:01:16

that’s helpful, thanks. Tempids are going to be used in most non-trivial apps, I think, so hopefully there will be a less clunky way to do that in the future. Maybe something in the om parser?

danielstockton14:01:32

yes, hope we'll see some standard practices emerge as things go on

danielstockton14:01:59

but it shouldnt be hard to refactor things later

nxqd14:01:25

I have the code below, it's quite straightforward, but somehow it doesn't work like it should.

static om/IQueryParams
  (params [this]
          {:dom-com/query [:a]})
  static om/IQuery
  (query [this]
         '[:navigation-point {:dom-com/props ?dom-com/query}])

;; (om/props this)
{:navigation-point :landing, :dom-com/props {}}
;; should it be 
;; {:navigation-point :landing, :dom-com/props [:a]}

anmonteiro14:01:31

@nxqd: it shouldn't if you don't have an :a prop in your app-state

anmonteiro14:01:46

also you need to define your parser etc.

nxqd14:01:53

@anmonteiro: I'm working on the same thing on app.cljs in your template. I try to use set-query! to change the component query then swap page with the new query from (om/props this).

dnolen14:01:15

@adamfrey: unlikely anything around that is going to change anytime soon, certainly not until after an initial release

dnolen14:01:35

post-processing of the :result server-side is just to be expected for many reasons

anmonteiro14:01:59

@nxqd: right but (om/props this) doesn't have a query

anmonteiro14:01:09

it has the props for the query of the current component

anmonteiro14:01:35

see the parser.cljs file

adamfrey14:01:35

@dnolen that’s fair. It probably will seem less surprising when there are a larger body of open source examples

nxqd15:01:07

@anmonteiro: I think I get it. Basically the dom-com/props read would pass the message down. And in the read function of a page component, I return something like this {:value query :remote true} it works as expected. And of course, we can add more things like caching to value later. is it correct ?

anmonteiro15:01:57

@nxqd: in the read function of a page component you return whatever props that component queries for, not its query

nxqd15:01:29

yeah it's true.

andrewboltachev19:01:40

Hi. Would om/Ident work for recursive components? I have category tree, where each node has :db/id, :category/name and :category/_parent (i.e. children) and couple of components that operates on it. But when I deref reconciler it just returns me old data. When I'm trying to mutate it using :category/by-id it gives me "No queries exist for component path " (only for first om/transact! call)

dnolen19:01:41

@andrewboltachev: we have devcards examples that do exactly that

dnolen19:01:57

so possibly a bug somewhere in what you are trying

andrewboltachev19:01:58

@dnolen: may I take look on that? These doesn't seem to be what I'm looking for: http://rigsomelight.com/devcards/#!/

dnolen19:01:23

@andrewboltachev: everything is in the Om Next repo - go look at it

andrewboltachev19:01:48

@dnolen: ok thanks

dnolen19:01:13

@anmonteiro: hrm I don’t know about the approach taken for displayName

dnolen19:01:29

@anmonteiro: far as I’m concerned we should just automatically compute this from the type name

dnolen19:01:01

being able to customize it to something else is just useless flexibility

anmonteiro19:01:22

@dnolen: React already falls back to the type name when you declare a component, e.g. om$devcards$core$Hello

dnolen19:01:44

@anmonteiro: right but that’s not what users want to see

anmonteiro19:01:47

@dnolen: what I really wanted with the patch was being able to customize it, as we could do in Om Core

dnolen19:01:16

@anmonteiro: I thought React had something like getDisplayName support no?

dnolen19:01:45

or where if displayName is a function it should work - I don’t recall the details

anmonteiro19:01:49

it does, by setting the string displayName in React.createClass

dnolen19:01:51

but I asked about this 2 years ago.

anmonteiro19:01:02

which is something we can't do in defui

anmonteiro19:01:16

hence the alternative I took in the patch

dnolen19:01:24

right so the patch is just a no go

dnolen19:01:28

not going to doing it

dnolen19:01:48

again just not interested in customization

dnolen19:01:11

only the repercussions for tooling

anmonteiro19:01:28

right, but the alternative is (set! (.. Component -prototype -constructor -displayName) "myName")

anmonteiro19:01:37

which is too verbose IMO

dnolen19:01:39

so computing a non-munged displayName property for the user would be acceptable.

dnolen19:01:43

but that’s about it

anmonteiro19:01:03

@dnolen: alright, so if customizing the displayName is a definite no go, I'll switch to computing a demunged name for it?

dnolen19:01:35

@anmonteiro: yes if you feel up for it

dnolen19:01:20

should be simple, just drop support for displayName method and just compute from the component name.

dnolen19:01:57

should probably include the ns name

anmonteiro19:01:22

@dnolen: it would make for more readable names in the console etc.

anmonteiro19:01:41

I'll take a stab at it

anmonteiro19:01:32

@dnolen: using (ns-name *ns*) to get the namespace for the component atm. is there a better way?

dnolen19:01:54

@anmonteiro: yes in a macro you can get get it out of &env

anmonteiro19:01:19

hah of course!

zalky20:01:44

So I've encountered some odd behaviour with recursive union queries, mutations, and the om parser. https://gist.github.com/zalky/efff0f87bdff7170382a .My example code is very similar to @anmonteiro's explorations here, http://anmonteiro.com/2016/01/exploration-patterns-om-next-part-1/, except that I used datascript in my recursive reads, and have mutations added. In a nutshell, all the queries and reads work fine on init. However when a child of a recursive union query is mutated, the union query that the read function receives gets wrapped in a vector, whereas before it is just {...}. I can't figure out if there's some assumption i'm missing (the read functions aren't that complicated), or maybe this is unexpected behaviour.

andrewboltachev20:01:01

I've copied recursive component example from here https://github.com/omcljs/om/blob/master/src/devcards/om/devcards/core.cljs#L242 and now I have Uncaught RangeError: Maximum call stack size exceeded error. Strange

andrewboltachev20:01:58

"Recursive problems" are trend LOL

anmonteiro20:01:04

@andrewboltachev: those examples are working, I would make sure you're running the current master

anmonteiro20:01:43

@zalky: the same, recursive union queries are not in alpha 28, you need to lein install current master

zalky20:01:11

gotcha, will give it a go, thanks

faceyspacey20:01:23

Does Om Next support query subscriptions like Meteor? If not, now how would you go about that?

dnolen20:01:48

@faceyspacey: it just depends on what you mean by “support”

dnolen20:01:10

it doesn’t get in the way of it, merge! is exposed to support stream oriented subscription

faceyspacey20:01:48

Do queries "out the box" maintain a subscription to the query, and therefore automatically receive updates?

dnolen20:01:12

“automatic"

dnolen20:01:21

very little in Om Next is automatic

faceyspacey20:01:24

Or is there a prescribed interface to turn it on?

dnolen20:01:37

but it’s not challenging to write whatever you need to make it work

dnolen20:01:42

Om Next was designed around this usecase

faceyspacey20:01:53

That's basically what I'm asking. Excellent!

faceyspacey20:01:22

I come from the Meteor community and in the midst of switching to CLJS

faceyspacey20:01:44

I'd love to be able to explain to the Meteor community an easy story to get the subscriptions they are used to.

dnolen20:01:04

right so you’ll find that Om Next is significantly less turnkey than Meteor in most respects

faceyspacey20:01:36

..i do find the query/mutation Relay-style interface way more turnkey than what Relay offers though.

dnolen20:01:00

mostly because everybody wants to do something a little bit different - so Om Next is more like a series of lego blocks you have to comprehend in order to put together some desired larger design

faceyspacey20:01:15

are there any docs that show an example of setting this up? Specifically with Datomic as the data source (i.e. rather than a client-only cache).

dnolen20:01:36

not really, still tied in alpha design work

dnolen20:01:08

you’ll have to be a bit up for adventure and figuring things out on your own for at least another couple of months

faceyspacey20:01:36

sounds fun. ok

dnolen20:01:54

there may be some Datomic examples floating around - people have mentioned this topic a couple of times

anmonteiro20:01:46

@dnolen: alright, just submitted a new PR; let me know if there are any issues with it

dnolen20:01:06

@anmonteiro: merged thanks!

anmonteiro20:01:35

@dnolen: cool

faceyspacey20:01:10

cool. i plan to be an evangelist for CLJS in the Meteor community. In fact I already am: https://forums.meteor.com/t/clojurescript-the-full-stack-meteor-of-2016/15694 ...There's a story going on in the Meteor community you may wanna be aware of: basically the Meteor community has been in the "dark" compared to the greater NPM community for a long time, coddled by all the full stack automation Meteor offers. As Meteor is going through a major change where basically React becomes their major view layer in place of their homegrown "Blaze" (among other similar changes), the community is in the process of an awakening. For example, we don't even support ES6 modules import/export, etc. We will in about a month, but we are very late to the party. Anyway, I took a lot of time off over the past 2 months to analyze all that's going on in the functional world and generally what's driving recent trends (CLJS, Om, Cycle, Elm, Haskell, etc). And my conclusion has been that CLJS, being essentially full stack, and since Om Next is getting so many things right regarding Relay and Redux-inspired features and also since it also easily supports "subscriptions" as I guessed, is the place to be for Meteor developers that expect a full stack subscription-based reactive system. Ultimately there's never been a competing solution for full stack reactivity, and CLJS + Om Next seems perfectly positioned to be the ultimate rendition of that. ...I understand that Om Next will likely require more boilerplate (i.e. the "lego blocks" you mentioned), but ultimately that's inevitable no matter which way you slice it, given the overall direction of the JS world has been toward a level of abstraction that allows for a maximum amount of choice and interchangeability (generally thanks to the design of NPM). So anyway, that's something the Meteor community has recently had to confront as superior options (mostly pioneered by Facebook) have emerged in the greater NPM community. My goal is to essentially help the Meteor community level up. I'm going to try to find the datomic subscriptions examples. If you stumble upon them, please let me know. I think you have a great marketing opportunity here by offering "full stack reactivity" and would love to continue evangelizing it.

dnolen21:01:39

@faceyspacey: sounds interesting - I know the Meteor devs but I don’t really follow it’s development much

dnolen21:01:08

I’m curious to see if Meteor users find ClojureScript interesting - assumes you’re interested in JVM on the backend

faceyspacey21:01:46

It seems you could get by using very little of it directly. I'm still getting started, but it seems like you can do most your work in plain Clojure without making use of the foreign function interface. Also, Datomic, in addition to subscriptions stuff, is particularly of interest, because like Mongo (which Meteor uses) you can query the database with the same language you're using for scripting on the client and server. Please correct my assumptions here.

dnolen21:01:21

Datomic is really only viable for serious work if your backend language is JVM based

dnolen21:01:27

otherwise you have to go through a suboptimal REST thing

faceyspacey21:01:25

Yea, but you're using Clojure. It seems you're pretty much abstracted away from JVM and Java in general. It seems you could get away with little concern for what's going on in JVM. My perspective is Clojure as the backend language is a good thing, it's the goal; it has the same appeal of Node where you can use one language on both the server and client. My assumption is you're hinting that there may be a reason we (Meteor devs) may not be interested in JVM on the backend--why wouldn't we?

dnolen21:01:46

Clojure doesn’t abstract away the JVM or Java at all

dnolen21:01:54

same as ClojureScript doesn’t abstract away JavaScript

dnolen21:01:21

I don’t know anything about the Meteor community - I’m not claiming to know anything about it

dnolen21:01:36

not beyond the high level marketing anyways

meow21:01:17

@dnolen: not sure I understand your point that clojure/script doesn't abstract away - that's how it feels to me as a dev

faceyspacey21:01:47

I just mean you're writing Clojure everywhere, not Java or JS. I'm assuming that's super obvious to you, and you're taking my use of the word "abstraction" to mean something deeper.

faceyspacey21:01:40

Basically, Om Next looks like React. Om Next is something us React devs can understand quite easily. On the server in Clojure, I'm assuming there's something similar, but it's Java devs for whom it's a natural fit.

faceyspacey21:01:46

not a java dev?

dnolen21:01:04

@meow: interop is first class

dnolen21:01:23

everything about ClojureScript is designed to work seamlessly with JavaScript

dnolen21:01:42

there’s a reason we all to piggieback on 30,000 lines of React without too many annoyances

dnolen21:01:26

@meow: of course there are non-Java devs in the Clojure community

dnolen21:01:53

but it is still the majority demographic

faceyspacey21:01:24

@dnolen: all I'm saying is it doesn't seem like you have to be interested much in JVM--you just have to be interested in Clojure/ClojureScript. Lots of devs are likely now gonna come to ClojureScript (and then on to Clojure) because of Om and their knowledge of React. Is there anything we should be aware of regarding the JVM? It almost sounds like you're warning developers that aren't coming to Clojure/ClojureScript from a JVM-first perspective. I'm personally ok with switching my entire stack to a Clojure one. That in effect is what I'm after--a unified stack.

zalky21:01:42

@anmonteiro: with only very small minor changes to your composite.cljs I can reproduce my issue. All I modified in your code was add a value property to each composite/leaf, and a mutate button that increments it: https://gist.github.com/zalky/26a9a2a5ea0836c522e4 As is the case with my code, mutates on the base component work, however mutates on children end up wrapping the union query in a vector, which breaks the reads.

zalky21:01:58

(and yes, I'm using the latest master now)

anmonteiro21:01:37

@zalky: I'll try your example

dnolen21:01:50

@faceyspacey: if you’re looking for a unified stack yes that’s a huge benefit, but note that most things in Clojure(Script) are in fact oriented around the JVM

dnolen21:01:57

same as Node.js being oriented around V8

dnolen21:01:03

direct consequence of the tech

dnolen21:01:17

@faceyspacey: in anycase this conversation isn’t really relevant for this channel now - better for #C03S1L9DN

andrewboltachev21:01:03

As for React 30 000 is a serious amount. Following one saying from famous DHH's talk "To become a good dev take one module from GitHub and read it from beginning to end" I wanted to read React (I recently stopped after 400 lines or so LOL). Do you think guys it's possible to become good e.g. Om Next dev only treating it as a "black box"?

dnolen21:01:21

you need to know React basics at least, but you don’t need to be a React expert

dnolen21:01:40

I don’t actually like the way that React is implemented, but the surface API is tiny and sensible

dnolen21:01:06

they are solving problems that no one really wants to solve - iOS, Android etc.

anmonteiro21:01:10

@andrewboltachev: Om Next's source is very instructive to read; David has said that he made it so that it could be read in 1 day

anmonteiro21:01:16

so why not do it?!

dnolen21:01:05

yeah reading the Om Next source is considerably less challenging in terms of the sheer amount of code that needs to be consumed

dnolen21:01:52

that said it’s a crash course in Clojure(Script) since it uses pretty much every language feature

anmonteiro21:01:30

@andrewboltachev: I'm not saying to attempt to read it in 1 day, you can obviously take as long as you want. But even if you only try to understand a few functions a day, it only adds to your knowledge in the end

meow21:01:51

reading any code written by @dnolen has given me insights and something to aspire to

andrewboltachev21:01:13

@anmonteiro: the only possible problem I can expect — 'cause of React, i.e. if I would face Om Next just talking to React, and I will not know what it means

andrewboltachev21:01:48

though if it only talks to "surface" so it's defenitely worth trying

anmonteiro21:01:19

@andrewboltachev: only React functions that Om Next uses are createElement, ReactDOM.render, ReactDOM.unmountComponentAtNode and stuff like that

anmonteiro21:01:44

(it also uses the prototype of the React.Component object in defui)

andrewboltachev21:01:00

@anmonteiro: aha, got it

rafd21:01:01

@andrewboltachev: i.... can't... even.... TIL

dnolen22:01:19

yeah that’s been in JS for a long time

anmonteiro22:01:40

@dnolen: thinking you might have forgotten to change refs->idents in transact*

dnolen22:01:54

@anmonteiro: probably

anmonteiro22:01:15

just something that caught my eye while going through it

geraldodev22:01:49

I'm getting Cannot Write from (t/write (t/writer :json) (om/tempid)) Do I need to make something special at client side for the marshalling of this special type to occur ? om.transit has a reader function and writer function, suited for the TempId case (it registers the handlers). So I need to say (t/write (omt/writer) edn) where t is cognitect.transit and omt is om.transit

anmonteiro23:01:40

@dnolen: not sure if this is the intended behavior in full-query

anmonteiro23:01:13

the example by @zalky kinda breaks there

anmonteiro23:01:46

getting a weird full-query

dnolen23:01:03

@anmonteiro: need a summary and something minimal

anmonteiro23:01:33

I know, thinking how to explain myself clearly

andrewboltachev23:01:21

I also had problems with full-query (I didn't use it, but stacktrace has shown where fail is), but might be my fault as well

dnolen23:01:23

full-query is not something to be used directly at the moment

dnolen23:01:55

but that’s neither here nor there if there’s an issue around it

andrewboltachev23:01:14

error msg is: "No queries exist for component path (ex0001.core/App ex0001.core/PerspectiveSwitch)" I've added this line https://github.com/andrewboltachev/om/blob/aboltachev/src/main/om/next.cljs#L1088 And it prints me... well, there's only [ex0001.core/App] key in :class-path->query map

andrewboltachev23:01:16

Should root components include queries of children?

andrewboltachev23:01:25

by "children" I mean ones what I'm using like ((om/factory FooChild) (om/props this)), this being parent component

anmonteiro23:01:03

@dnolen: the issue is not in full-query

anmonteiro23:01:16

atm I've narrowed it down to build-index in the indexer

anmonteiro23:01:15

but I still can't explain it properly; all I can say is that when the mutation happens in a recursive union, the read method is fed the wrong query

anmonteiro23:01:52

it has something to do with the paths/classpaths, but I'm still investigating further

anmonteiro23:01:08

narrowed down further to query-template

anmonteiro23:01:15

this probably needs support for union recursion