This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-03-04
Channels
- # admin-announcements (3)
- # alda (4)
- # beginners (30)
- # boot (116)
- # cbus (5)
- # cider (20)
- # clara (10)
- # cljs-dev (12)
- # cljsjs (41)
- # cljsrn (9)
- # clojars (6)
- # clojure (131)
- # clojure-bangladesh (5)
- # clojure-colombia (2)
- # clojure-dev (9)
- # clojure-ireland (4)
- # clojure-japan (3)
- # clojure-norway (10)
- # clojure-poland (6)
- # clojure-russia (59)
- # clojure-sg (1)
- # clojurebridge (2)
- # clojurescript (76)
- # clojurewerkz (4)
- # css (6)
- # cursive (21)
- # data-science (24)
- # datomic (27)
- # emacs (9)
- # hoplon (68)
- # jobs (2)
- # jobs-rus (1)
- # ldnclj (10)
- # lein-figwheel (9)
- # leiningen (21)
- # off-topic (5)
- # om (232)
- # onyx (63)
- # parinfer (2)
- # proton (25)
- # re-frame (12)
- # reagent (39)
- # untangled (6)
- # yada (122)
looking at the om next todovc example... i've set up figwheel and a ring server+datomic so far and both are working fine but how do you use them together?
(om/db->tree [:y] {:x {1 20} :y [[:x 1]]} {:x {1 20} :y [[:x 1]]})
is get resolved to {:y [[:x 1]]}
. I was expecting {:y 20}. Surely my understanding is flawed. Can something throw some light on it
@tawus if my understands is correct, the query must use join explicitly to get ident/link resolved, e.g. [{:y [:x]}]
I'm trying to figure out what I need conceptually on the backend to make an Om parser for a remote. Swanodette has a tutorial here which showcases a bunch of read/mutate functions that take an env
with a conn
key and a query
key. For example:
(defmethod readf :todos/by-id
[{:keys [conn query]} _ {:keys [id]}]
{:value (d/pull @(d/sync conn) (or query '[*]) id)})
But what does that conn
key represent? How do you know that the env
passed to you from the front-end (which I assume is an ast
map) is going to have that key on it?Here is swanodette's actual tutorial: https://github.com/swannodette/om-next-demo/blob/master/todomvc/src/clj/todomvc/parser.clj
How does it get into a the env
argument passed into the parser?
george.w.singer: i do know that the database connection is stored in the system component, servlet-system i believe
@george.w.singer its in server.clj, in api fn where the parser is invoked
I'm looking at server.clj and I still don't see where/how the back-end parser knows anything about conn
(specifically, how conn
is passed in as a key of the env
variable w.r.t. the read/mutate functions)
george.w.singer: https://github.com/swannodette/om-next-demo/blob/9d096ce1f9f590a4ac039251d89133d8b958b211/todomvc/src/clj/todomvc/server.clj#L60-L66
So before the req
is handed to the parser, it is assoc'ed with a :datomic-connection
as well as whatever conn
ends up being elsewhere in the code key/value
I'm assuming conn
will eventually :conn
And that's how it ends up in the env
variable passed into the parser
is that about right?
In case curious, here is directly where :conn
is added to env
:
(defn api [req]
(let [data ((om/parser {:read parser/readf :mutate parser/mutatef})
{:conn (:datomic-connection req)} (:transit-params req))
data' (walk/postwalk (fn [x]
(if (and (sequential? x) (= :result (first x)))
[(first x) (dissoc (second x) :db-before :db-after :tx-data)]
x))
data)]
(generate-response data')))
The call to om/parser
returns a parser which takes env
as its first argument (which, in this context, is a map with the :conn
key).
Is it possible to define a multimethod as a (let...)
binding?
The purpose for doing so is that I need to invoke the <!
macro within the definition of a multimethod's method. So I'm trying to put the definition of this multimethod within a (go ...)
block. And I know that I can put a go
block within a let
statement. So if I could define a multimethod as a let binding
(wrapped inside a go block), I would safely be able to use <!
within the multimethod.
@george.w.singer: this is material for #C03S1L9DN
@iwankaramazow: Yes, sorry for the off-topic post. I got it resolved elsewhere.
Question RE: sending the result of a parser function from the back-end to the front-end:
When I send a map that contains a go block as one of its values from the back-end to teh front-end
my back-end crashes
I THINK it's because I'm sending the map via cljs-transit
Does it now allow the sending of channels over the wire?
You'll need to extend Transit to handle channels
You mean use something besides Transit?
When I actually think about it, it's insane to think that transit could send a channel over the wire
What if it's not populated yet?
The client would never get the value
You'll probably don't want to send channels over the wire though
Honestly I don't know
it doesn't seem to be worth the effort
there's also no sane reason I can think of why someone would to that
Went with another solution
@dnolen: query is passed into path-meta
but not used right now, is it passed in because what we should be doing is only marking data that is tied to a piece of the query? https://github.com/omcljs/om/blob/master/src/main/om/next/impl/parser.cljc#L162
@jlongster: that's correct, the query is not used because if I remember correctly David just put it there in a "prep" commit
git blame
will tell you if I'm right
ok cool. This may test my understanding of queries but I'm gonna try to implement it
that's probably something to spend a little time on
It didn't look too hard
but it's not a very simple problem either
feel free to ping me if you need any help
@anmonteiro: yeah, already have some basic questions... where is the path updated? I see that it adds the :path
key initially as []
but I don't see where it appends to it
@anmonteiro: oh, duh path-meta
creates the path... obviously I don't really know what this is used for yet. I guess something else can put a different initial path in env
if it wants to, but nothing else does that right now
@jlongster: this path-meta is what is attached to components
in omcljs$path
represents the data path of the component
yeah, I thought this path was constructed somewhere else and path-meta
recursively tagged it, but it does both
i.e.
(defui Child
static IQuery
(query [this]
[:foo :bar]))
(defui Root
static IQuery
(query [this]
[:child (get-query Child)]))
in this case, Root has path []
Child has path [:child]
are things like recursive and union queries the things that make this complicated? If I just make it so it at least doesn't recurse in more basic queries, it should be simple right?
unions are probably not complicated
since every union item has the same data-path
both the union component and the leaves
recursion has repeated keys, yes
@anmonteiro: thanks
@anmonteiro: this is going to make path-meta
aware of query semantics, right? it's going to "recurse" down into the query along with recursing down into the data. do we already enforce returning data in the right way in parsers, i.e. [:foo {:bar [:x :y]}]
-> {:foo "foo" :bar [{:x 1 :y 2}]}
parsers right now can return whatever they want
I guess a better phrasing is: parsers should not arbitrarily execute sub-portions of the query in ways that don't match those rules
@jlongster: I think it's not enforced
and I also think it wouldn't really matter
if you write a query for a component, you really are going to return the right keys to match the query
if you at least use the default db format you're going to get the right keys if you do everything right
Datascript users will also want to return data that matches the query
especially because they're using the Om query directly against the database, I think
(d/q '[:find [(pull om-query) ...]])
the pull syntax works for most cases, I believe
I don't think they are, but I'll let anyone that has used Datascript more than I did answer
I ran script/figwheel.clj
, where do I point my browser again to get figwheel connected?
I’m running into a problem with transactions and reconciliation and would like to run it by someone with knowledge of Om.next internals. Problem: After I transact! the reconcile!
function is called not once, but twice. On the second time in reconcile
the :queue
of components to update is empty so I trigger this condition and rerender from the root with my unparsed app-state https://github.com/omcljs/om/blob/20f790d686eeb716275148dc1fa3349b3cfe800d/src/main/om/next.cljs#L1590
Explanation: The reason I hit reconcile!
twice is because my transaction causes some components to leave the screen, triggering their componentWillUnmount
callback here, which updates that reconciler state: https://github.com/omcljs/om/blob/88c62914e8948b329d2829c740e732eb4a95b7ac/src/main/om/next.clj#L153
@adamfrey: and what's the problem that it causes you?
My app is fine for a fraction of a second after the transaction, but then it rerenders from the root without parsing the app state
FWIW, there's a pending PR that'll fix unnecessary calls to swap!
in componentWillUnmount
(https://github.com/omcljs/om/pull/638)
that seems like a bug, can you make a minimal case?
((:render st))
is just React/render which should not re-render unnecessarily
I should definitely try this out in a web app and see if it is react-native specific. I never ran into this problem on the web.
@adamfrey: I'm happy to look at a minimal case if it turns out to happen in web too
well applying @jlongster’s PR fixed the problem, actually
I feel like that triggering a rerender when something unmounts isn't the best idea in general
@adamfrey: right, but if the component has a custom query your problem will come back again
that’s true. If I get time this weekend I’ll try a minimal case and for now I’ll just keep that in mind
thanks!
@anmonteiro: a very crude version that seems to work for basic queries https://gist.github.com/jlongster/1c661626a0860022ef26 will need to add support for union and recursive queries. look like the right track though?
@jlongster: give me 30 min or so and I'll get back to you
I know the feeling
and I hate that feeling 😛
is there any way to access the history of the reconciler?
for basic undo/redo?
@iwankaramazow: not publicly, no, there's an issue for that though: https://github.com/omcljs/om/issues/407
I mean, there's from-history
I was looking at a simple undo/redo in an excel spreadsheet like application.
You might also want to look at the raw Cache type
ah ok thanks
somehow getting those UUID's from transactions would come in handy
@anmonteiro: in the first case where x
is a map, the current query
would actually be a map instead of a vector in the case of unions, and I'm not sure what part of that union query to pick off when recursing down. just leaving that here, no need to respond until you take a look.
@anmonteiro: there are many things wrong with the initial attempt I posted, no need to look at it. I'll make another attempt soon-ish
@jlongster: oh OK thx for the heads up
was going to look now
yeah, I forgot things like joins that return a single item don't return a vector, they return just the item
I’ve got an interop question (if anyone has a minute). How do you pass props between om.next components and normal react components? It appears the om is passing a PersistentArrayMap as their props, but normal react components can’t read that.
#js { }
?
well, wouldn’t that convert the CLJ data structure to a javascript data structure?
Meaning if I have a tree of components (om.next —> js-react —> om.next) I would end up with a javascript data structure at the final om.next component.
@seantempesta: it's a bit tricky
are you passing om/props
?
so for react components just pass (.-props this)
but I also need to pass normal js parameters so the js-react component can read them
there's no way around it (I think)
in React.js -> Om Next you'll probably need to get the "omcljs$value"
from the props
ah so in the grandchild you can have access to cljs data structures?
without converting them back
well, they don’t really convert back
clojure is so much more rich
@seantempesta: are you still having problems with what I've said?
well, I guess I don’t really understand
which part?
If I go from cljs -> js then there isn’t a omcljs$value
so:
1. don't pass (om/props this)
to the JS component
but whatever's in (.-props this)
, which is a JS object
ah, I see
let me try that
so I just need to merge the js props with (.-props this) and pass that to the js-react component?
@seantempesta: merge
won't work with JS objects
you probably need to set!
the fields you want in the JS object's props
ah, gotcha. I’ll work on that.
@seantempesta: do you need access to transact!
or set-query!
in your vanilla React component?
no, but I do in the grandchild om.next component so it has to be passed by the js-react component
basically, the middle js-react component is a router. So it needs to be able to pass everything from the om.next root component
ah, React-Router?
react-native-router-flux
yeah, it’s kind of a pain, but being able to change screens on my app is kinda important.
No idea how routing works in React Native, but I feel your pain 😄
okay, so this is what’s surviving in the grandchild om.next component when I call (om/props this)
:
dispatch: undefined
hideNavBar: true
name: "_login"
omcljs$depth: 0
omcljs$instrument: null
omcljs$parent: null
omcljs$path: cljs.core.PersistentVector
omcljs$reconciler: om.next.Reconciler
omcljs$shared: null
omcljs$value: om.next.OmProps
plugin: ExRouter(props)
route: Route
sceneConfig: Object
title: "Kidlink"
__proto__: Object
So, it successfully transferred the om props. How do I convert them back to what I’m expecting (ie a cljs data structure)?
You could try js->clj
, that isn't the most efficient
function out there
hmm, that doesn’t seem to work: No protocol method IEmptyableCollection.-empty defined for type : [object Object]
Sorry, no idea how to solve that
@seantempesta: what do you need in your grandchild?
both the router props from the js-component and the om-next props so I can use transact and query
can't help you with the router's props, where are they?
in the above list it’s everything that isn’t “omcljs$"
@seantempesta: so those you can get
but I guess I don’t understand why when I called (om/props this)
I didn’t get back a clj data structure
@seantempesta: this might seem strange, but try doing (om/props (om/props this))
Assert failed: (component? component)
oh, right
one second
So I need to trick om into thinking it is an om.next component?
(defn ^boolean component?
"Returns true if the argument is an Om component."
[x]
(if-not (nil? x)
(true? (. x -om$isComponent))
false))
Do I just need to append om$isComponent true?
no, one second
well, that would probably work as well
okay, I’ll try that
(om/unwrap (om/get-props (om/props this)))
this should work
holy shit! it worked!
you’re a golden god!
@anmonteiro: So, calling (om/transact! this …)
should work too? Or do I need to do any conversions?
@seantempesta: in theory, yes
Is there a way to replace the :app-state
of your reconciler ?
the wiki mentions replacing the initial app-state, not the current app-state
@anmonteiro: Nope. When I call transact I’m getting an error. In (defn transact* [r c ref tx]
r is null. That’s the reconciler, right?
The reconciler is read from the props, right?
found it in Om's source => merge!
Okay, so I fixed the problem of the reconciler being null, by overwriting the props:
(let [om-props (om/props this)]
(set! (.-props this) om-props)
but now I’m getting this error: No queries exist for component path
from (defn full-query
which I’m guessing (from it’s description) returns the full query path back to the root. Which isn’t going to work, right? Since I’m going through a non-om router?
If your router switches out its children components, you have to make sure you set the query at the root om component above the router
A No queries exist for component path
in 99% means you 'steal' the query of a child
So no queries can be defined below the root because I’m using the router.
I guess that’s fine.
I think you can
that's what set-query is there for
Well, I didn’t even call set-query!
. I called a transact!
(which oddly enough succeeded)
In my root component I have something like (into [] (concat root-query [{:route-root child-query}]))
the :route-root
join makes the query valid
hmm, I’ll take a look at that. It’s tough debugging a problem when you don’t understand the underlying idea. Maybe I should re-read the om-tutorials again.
(defui Child
static om/IQuery
(query [this]
[:prop]))
;;wrong, you steal the child's query, => no path exists for component...
(defui Root
static om/IQuery
(query [this]
[(om/get-query Child)]))
;;valid query
(defui Root
static om/IQuery
(query [this]
[{:root (om/get-query Child)}]))
Oh, I think I see what you’re saying
a router component could prefix every Child
query with :root
here, so it's a valid query in the end
In theory if you put your native js router in between Root & Child, it shouldn't make a difference
Okay, I checked and the omcljs$path
is empty on my child component. I think that’s what’s causing the problem. Anyone know how this is supposed to be populated?
Ugh. This is all feeling too hacky. I’m going to take a break and then I’ll just try implementing my own router as an om.next component. Thanks again guys for helping me work through those bugs!