This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-11-23
Channels
- # admin-announcements (38)
- # announcements (1)
- # aws (1)
- # beginners (195)
- # boot (1)
- # business (3)
- # cider (100)
- # cljsrn (37)
- # clojure (99)
- # clojure-russia (69)
- # clojure-switzerland (1)
- # clojurescript (120)
- # datavis (26)
- # datomic (23)
- # devcards (4)
- # editors (38)
- # hoplon (18)
- # ldnclj (27)
- # lein-figwheel (28)
- # off-topic (50)
- # om (329)
- # onyx (255)
- # portland-or (1)
- # re-frame (8)
- # reagent (18)
- # spacemacs (5)
- # testing (1)
In the remote synchronization demo, why is ast
passed to :search
in the read
:search/results
multimethod? If I replace ast
with true
it seems to work just the same.
@tyler: Returning true means you want to send that portion of the query on to the remote. Putting an AST node there allows you to modify the query in some way.
the former was the original (only) way. The latter is the newer more flexible method
where can you modify the query? It looks like when you pass either the ast or true, you end up with the same input to the send function.
I thought you passed the ast so you could modify it downstream thats what was throwing me off
So in the example, you don’t need to actually pass the ast to :search its just showing you that you can, and you could modify it before doing so?
So if you modified the query string in the ast you return from a remote key, the remote parser would see the modified query?
Was referring to the actual query string thats getting sent to wikipedia in the example but I get what you’re saying. Thanks, I appreciate it. That really clarifies things.
@anmonteiro thanks, just saw your message, it solved my problem! I am still somewhat confused about how transact!
works, because I thought it implicitly re-rendered anything that this
queries. In the function passed from Root to the subcomponent, this
was passed as an argument from Root, so I thought it would re-render everything without me having to provide additional keys.
Hello, learning om-next, any tutorials or good example projects besides referenced from om/wiki?
shows how to sync with a remote datomic database
well I’m going to integrate om-next with iOS application, where datomic unfortunately not a case, so the storage would be custom, but thanks in any case - currently I appreciate any examples
you don't have to use datomic but you'd have to write quite different read and mutate methods on the backend
im not aware of any examples of that yet, datomic is much easier
yep, got it
btw - do you know how stable is om-next currently? I know it’s an alpha and API could change, but for small and simple things?
Trying to avoid big changes at this point, unless there's some huge problem - haven't seen that yet
Good, thanks
@dnolen: I think it would be a good thing to have a "db-path" key for the parser. @tony.kay is using the env variable to store the :db-path, but as a datascript user, my env is the database atom. https://github.com/awkay/om-tutorial/blob/b9570df72f0d85c832fc576dd26aa7afbd871c76/src/main/om_tutorial/parsing.cljs#L31
as a datascript user, i would use the :db-path key to pass :db/id s
Can someone explain the concept of "factory" in om-next, I'm having some troubles wrapping my head around the various components. 😕
a fn that creates instances of a component
Theres also this code in the Om.next tutorial under the parser section: (in-ns 'om-tutorial.core) (defn read [{:keys [state] :as env} key params] (let [st @state] (if-let [[_ v] (find st key)] {:value v} {:value :not-found})))
find returns the map entry [key value] rather than just the value
but in this case, clearly the key isn't needed
@jethroksy: please note there is a difference between using find
vs get
on this case, for example: (find {:a nil} :a)
returns [:a nil]
, which will pass true
on the if-let
, if you used get as (get {:a nil} :a)
that would return nil
that would make the if-let
go false
good point @jethroksy
Ah good catch @wilkerlucio thanks!
sorry, i didn't mean to highlight you again
@thomasdeutsch: not sure I follow, what would this value be? And what’s stopping you from tracking this yourself (honest questions).
@dnolen: if i call a parser in my read function, to parse the subquery - i think in most cases, i would like to tell the parser on what db/id or path in the env the parsing should take place. My env could be a map like: {:current-id 122 :db state}
but i think that telling a parser on what entity/sub-tree to parse on, would be more idiomatic.
@thomasdeutsch: this is what :query-root
is for
@dnolen: no way 🙃 will try this out with datascript. thanks
@dnolen: do i need an om-version higher than alpha23 ? because my reader in the om/Ident vector will not get called.
@thomasdeutsch: I do not know what you are saying
what is the use-case for query-root?
@danielstockton: what @thomasdeutsch just said
good day,
which channel is the best place to ask questions about natal
and react-native
?
@misha: #C0E1SN0NM
@artemyarulin: there is a #cljrn channel now with people experimenting with om.next + reactnative or reagent/RN.
@thomasdeutsch: @dnolen I don't think that is what Thomas is talking about. He referred to my parsing code, which is tracking it's way through the default database format state path while doing recursive parsing. Query root is for talking to the server and stripping off a prefix of that path.
at the start of the parse. There is nothing automatically done for us from our read functions when we call the parser again
yes, I just didn't realize you intended us to use it that way, so my examples use one I invented called :db-path
"if parse hits a key that’s an ident it will set this to :query-root
" <- !
When using get-node
do we always use it like this (om/get-node owner “name-of-component”)
?
@dnolen I was able to fix the problem I was having yesterday by adding keys to the query expression of transact!
However I don't understand why that was necessary, because my root component was querying everything that needed to be re-rendered. Using (om/computed)
I passed down a function that calls transact!
using the root component as the initiating component, so I thought implicitly it would re-render everything the root component queries. Why is that incorrect?
sorry if that is unclear, this is the code https://gist.github.com/prbroadfoot/b8801772d2a41409ef86
@paulb it should work but I noticed there were some subtle issues with transact!
you may want to try with master
as far as the bigger point about implicitly re-rendering everything used by the query - absolutely not
ok thanks, here one string is replaced by another, so it should re-render, so I suppose it's a bug
@paulb there may be a bug if you try transact + update-state! but I’m pretty skeptical
I’m having trouble getting my :send
function to be called. I’m probably doing something wrong. My app was written before :remotes
were specified when setting up the reconciler, and all you had to do was return {:remote true}
from the parser. I thought all I had to do was add :remotes [:remote]
to my reconciler setup, but my send fn isn’t being called
Is there anything obvious I’m missing in getting remotes working with Om version 23?
I have a scenario here where I have 2 different representations for the same data, how can I proper setup my query? the query: (query [this] [{:app/current-track (apply conj (om/get-query LoopManager) (om/get-query TrackLoopOverlay))}])
, it works when it renders the LoopManager
, but when I try to render TrackLoopOverlay
I get No queries exist for component path (youtube-looper.next.ui/LoopPage youtube-looper.next.ui/TrackLoopOverlay)
@wilkerlucio: that query doesn’t make any sense to me
ah ok so I sorry I see what you’re trying to do will make a QueryRoot
but yeah you cannot combine queries like that
my scenario is that I have one resource (track), and at the root component I have 2 components that uses different information from this same entity, one of then uses :track/loops
, the other uses :track/duration
(simplifying to make a point), I was trying to merge a single query to fetch data for both and then pass the same props for both
@wilkerlucio: you just can’t do it that way
Is it documented somewhere that components can return UnionExpr? I was confused as the parser docstring mentions that most apis expect QueryRoot and then Union example shows query methods which returns UnionExpr.
@juhoteperi: not beyond the tutorial
ok, you have a suggestion on how to deal with this scenario?
@wilkerlucio: don’t combine queries
or make the top level query and remove the query from below and make those components pure and query-less
ok, makes sense
thank you
if you start doing stuff like this obviously it’s not possible for Om Next to see the association
yeah, makes sense, little by little getting used to it
in Om Next they are data so these kinds of data oriented things seem like they could work
I just put this line in an app dom-node (om/get-node owner)
and it throws an error Uncaught Error: Invariant Violation: findComponentRoot
👉 translated the :query-root
tree example to datascript: https://gist.github.com/ThomasDeutsch/0f31328a72255fdc07f1
@dnolen: noticed a typo in the conditional for https://github.com/omcljs/om/wiki/Remote-Synchronization-Tutorial#code
(when-not (and (string/blank? query)
(<= 2 (count query)))
{:search ast})
Should be:
(when (and (not (string/blank? query))
(<= 2 (count query))
{:search ast})
@thomasdeutsch: cool so it just worked for you???
@dnolen no need to check my example, upgrading from alpha22 to alpha23 fixed the bug I was seeing
(let [query "h"]
(not (and (clojure.string/blank? query)
(< (count query) 3))))
;; true
Don’t you want the query not to run unless theres at least 2 chars?isn’t not blank? always going to return true regardless of the count of query if its not blank? and if it is blank, what is the purpose of the count of the query?
@dnolen: yes, it worked. But i still use the datascript pull api in my reader - can not do this for generic solution.
hey everyone, partway through building a non-toy thing with om.next i'm confused.
david's been saying, and my understand was
that components and queries are 1-1
but it seems like that's only true for the root component
and that all child components props are passed into the factory, rather than parsed from their queries
i understand the need to be able to get the entire application query in the root component, but does this mean that if i want user data somewhere down the component tree, i have to pass it all the way down?
i had assumed that you could just write a query for the user at any point in the component tree
so is it possible to do something like this?
my experiments suggest not. that you must pass props into (navigation), and that the root component (Dashboard), needs to build the entire query
although some of the code around set-query! makes me think the above should be possible
@thomasdeutsch: you mentioned calling the parser in read functions, are you doing that to get top level queries further down the component tree?
I think yes, Dashboard does need to build the entire query there. To do that, you use (om/get-query Navigation) within Dashboard’s query, so you don’t need to repeat the query entirely or anything, but you do need to reference it.
so what if multiple child components want to define the same query with different parameters?
i can't have a query like this, correct?
(query [this] [(:user/find {:uid "dorothy"}) (:user/find {:uid "lion"})])
you'll end up with {:user {:uid ?}}
*:user/find
@dnolen: as far as i can understand, :query-root
can help getting my data after a mutation. But can it help me for the initial read
(defmethod read :tree
[env key params]
(let [{:keys [state parser query query-root]} env
group (group-by keyword? query)
keywords-value (d/pull @state [{key (get group true)}] query-root)
joins-value (parser env (get group false))] ;; this is where i need to pass a new query-root to the parser
{:value (merge (first keywords-value) joins-value)}))
@tony.kay i using a :db-path
he is adding to the env.@thomasdeutsch: do you have an example of a query you're parsing with that?
@pleasetrythisathome: i do not think that your query makes sense. have you looked at datomic-pull for some advice? http://docs.datomic.com/pull.html
yea i know datomic pull syntax well
@pleasetrythisathome: in your query you could use a function like [(:user/get-multiple {:uids ["dorothy" "lion"})]
but if you already have a uid - why do you need a find? and why not using a lookup-ref (in datascript)
sure you could definitely do what you're saying, my point was not about the particular query, but is about multiple child components that want different data
for example
say i have a root component, and two child components that both display lists of something, but maybe want to display different numbers of items, or different fields from those items
it seems to me, that you currently have to merge child components queries into the root component query, and then pass the data to the child components as props
i would merge the queries in the parent, yes.
so you might have something like this
but that won't work, the second query to :messages/list will overwrite the first one in the data returned from the parser
it is not easy to tell. i am thinking of https://github.com/omcljs/om/wiki/Queries-With-Unions . Since this is a situation where you want to say that a MesssageDetailList is from another type as MessageOverfiewList
hmm ok didn't look at that carefully enough. although in the example, the read function doesn't look like it's doing anything with the union query
it's just returning the list of items
regardless of the multiple subqueries in the union
and then creating a dashboard item with all the data for each
and then dispatching on type and creating the correct type in dashboard item, but each type (Graphic, Post, etc.) isn't getting the specific data it asks for, they'll all getting whatever data just happens to be in the item
or am i reading something wrong?
the parser doesn't automatically call the read function for the unions
in fact, the unions break readers designed to take a query (for datomic/datascript pull for example)
in the wiki example, and in the tests https://github.com/omcljs/om/blob/master/src/test/om/next/tests.cljs#L816, the reader isn't looking at the union query at all
I was trying to minimize an issue that I was having about component updates, I end up falling back into the first example at Om.next quickstart page, and even so the component still not updating correctly
example ready for devcards ^^^^
did I miss something?
@dnolen: it seems like unions should be read for each union case in the map, and then merged back together
@pleasetrythisathome: You need to handle your own query reading. Your example is perfectly valid, and one way to handle it is a recursive parser. i.e. if you had a read function that handled :message/list
and returned the results of various queries, you'd be good.
@bplatz: right the different keys thing makes sense
which is the purpose of unions queries
As you are returning a map... so the same behavior would apply if you overwrote a key in a map.
so i suppose you could write conditional logic in your parser that detects whether or not the query is a union and does the appropriate thing
the union example in the wiki works because of the normalization process through idents
I don't think you need union in your case, but I don't have a full grasp on what you are doing.
which i think isn't really the way i'd think about unions
Then in your parser for :messages/details
and :messages/overview
, which might use the same default read...
right but then you have to write another read dispatch method any time you want to have multiple components executing essentially the same query
if you do it with unions, you would think something like this would just work, without the ident stuff
>>>(defui MessageOverview static om/IQuery (query [this] [:message/title])) (defui MessageDetail static om/IQuery (query [this] [:message/title])) (defui Messages static om/IQuery (query [this] [{:messages/list {:message/details ~(om/get-query MessageDetail) :message/overview ~(om/get-query MessageOverview)}}]))
(defmethod read :messages/details
[env key params]
(let [{:keys [state query parser]} env
recursive-read-value (parser env query)]
{:value recursive-read-value}))
I just typed that... so it might not be completely accurate... but to illustrate the concept.
oh that's cool
actually you could have that as your default read
or the default read when the query is a map
so the recursive read stuff makes sense, but i'd like to understand how to do something similar with unions as well
in the above example, the read function would get called with the query as
[{:messages/list {:message/details [:message/title],
:message/overview [:message/title]}}]
sorry the query portion would just be
{:message/details [:message/title],
:message/overview [:message/title]}
so if you had a read function like
(defmethod read :messages/list
[env key params]
(let [{:keys [state query]} env]
{:value (map #(select-keys % query) (:messages @state))}))
things will break
or in my case (datascript)
(defmethod read :messages/list
[env key params]
(let [{:keys [state query]} env]
{:value (d/q '[:find [(pull ?e ?selector) ...]
:in $ ?selector
:where
[?e :message/uid]]
(d/db state) query)}))
Unless you are rendering those items as one list, I don't see why are you are trying to use a union.
@pleasetrythisathome: you don’t need a union
and you don’t need to merge into the parent if you’re willing to divide up the component responsibilties
i'm really just trying to understand the different ways you can structure data
by divide up component responsibilities, you mean that the components have their own independent queries that are not included (either in the first level of the query vector, or nested somehow)
of the root component
there was nothing wrong for example with what @wilkerlucio wanted to do earlier if he was willing to dupe query information into children
Using datascript I think you'll have to keep multiple reads, unless you have your database heavily referenced and mimicking part of your UI. If so, then great, a gigantic pull
might work.
@pleasetrythisathome: and no there’s no such thing as “independent” queries
so that was my initial point of confusion. it seems like the only component whose props are created from its query is the root component added to the reconcilcer
and all other components are constructed with their factory functions which take and set props
so that's where i'm confused, it child component props aren't computed from their queries, or is there some way that gets done i'm missing
3) your components are assigned to take different parts of that tree (by having returned queries themselves)
right, so say i want to get logged in user data down a deeply nested component tree
i have to pass it through all of the children, right?
so those sound like conflicting statements to me
when you say "anybody can link to anything whenever they want"
i can have a component way down the tree with a query that has a top level parser key?
yes that makes sense. so would your suggestion for the above case where two subcomponents define different queries that use the same parser method would be to give them different keys in the root component query, and define a recursive parser for those keys?
alright makes sense
it will take a while for people to see this but many problems can just be fixed by making up links
and the links are created by ident?
i saw that in the union wiki
and where are you using these? in place of keywords in the query syntax? and then you can just have more flexible parser dispatch?
@pleasetrythisathome: sure that’s one possibility but this isn’t my idea
i'll dig into the falcor docs more
thanks, need to percolate and play around for another day
i'll get back to you
cool, i'll check it out
there’s probably some edge cases here because people aren’t pushing the link bits very hard yet since in many of the examples thus far, they are something of an implementation detail
but it’s how you can get at some related information regardless of your location in the tree
Hey, all. I would have posted this a few hours ago, but Slack was having issues. I added functions to the om.next
API to deal with a reconciler’s history. Here’s a diff: https://github.com/omcljs/om/compare/master...lambdahands:master?expand=1 Thoughts?
@lambdahands: the history stuff just needs more thought than simply exposing it
happy to engage in discussing what I’m thinking about, but it’s not small amount of work
Yeah, I figured. Those functions helped me out in the short term. I’d love to hear about it, though. I’m interested in doing something a little more challenging.
so this not fully formulated idea but I want users to be able to use the cache for far more sophisticated forms of state management
it would be nice to be able to get a bookmark somehow, and when the server errors, revert to the bookmarked state and show error message
until then not that interested doing more with the history cache then I’ve done so far
it’s a little debugging tool - and people can hard code little helpers if they like in the meantime
Hmm, definitely an interesting problem. The first image that popped in my head was a branching mechanism.
yeah not excited about branching at the moment (at least as default) - and like the reconciler we may just need to defer to defaults + pluggability
That’s no problem! It’s insightful and elucidating to see and take part in these discussions and the implementations that develop. I remember a short IRC chat we had a few years ago when core.async first landed in CLJS and there was plenty of “I don’t know” back then. 😛
I think there’s a really cool idea here around the history cache and it would be nice to see somebody run with it
Absolutely. And I think the reach of om.next is on another level, especially considering my field of work which gravitates toward interaction design– lots of cases where I want to build functional prototypes which can be put in front of users and tested against many application states. I envision history playing a huge part in that.
@lambdahands: agreed there, probably what I will do in the near term is make sure history works appropriately for devcards
@dnolen: I'm curious about your thoughts on Allen Rohner's foam library (https://www.youtube.com/watch?v=fICC26GGBpg) and how it might work with Om Next. In the long term, do you see the idea of server side rendering becoming something that folds into Om Next, or is it something that should be pursued external to the core? Mainly curious because so many of the things that Om Next ties together are also things that haven't had a nice story to combine in the past, so wondering if there is also a nice way to get the idea of server side rendering in there too.
@shaun-mahood: I already said publicly that I would like to see something like that integrated
@dnolen: Fantastic, I had this vague recollection of you sounding interested during the questions but am only now starting to process things from the conj