This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-06-12
Channels
- # admin-announcements (1)
- # arachne (3)
- # cider (11)
- # cljsrn (5)
- # clojure (26)
- # clojure-android (10)
- # clojure-greece (8)
- # clojure-russia (5)
- # clojure-spec (7)
- # clojure-uk (3)
- # clojurescript (16)
- # clojurex (38)
- # core-async (1)
- # css (3)
- # cursive (42)
- # dirac (2)
- # hoplon (28)
- # keechma (1)
- # lein-figwheel (2)
- # leiningen (1)
- # mount (3)
- # om (132)
- # onyx (46)
- # re-frame (53)
- # reagent (17)
- # spacemacs (7)
- # specter (50)
- # untangled (2)
- # yada (3)
@jasonjckn: I think you're looking for:
(om/db->tree [:foo] [[:bar/bars-by-id 1] [:bar/bars-by-id 2]] {:bar/bars-by-id {1 {:foo "foo1"} 2 {:foo "foo2"}}})
That gives you:
[{:foo "foo1"} {:foo "foo2"}]
Or with the full query you could do something like:
(om/db->tree [{:bar [:foo]}] {:bar [[:bar/bars-by-id 1] [:bar/bars-by-id 2]]} {:bar/bars-by-id {1 {:foo "foo1"} 2 {:foo "foo2"}}})
That gives you:
{:bar [{:foo "foo1"} {:foo "foo2"}]}
Take a look a the source or docs:
om.next/db->tree
([query data refs] [query data refs map-ident])
Given a query, some data in the default database format, and the entire
application state in the default database format, return the tree where all
ident links have been replaced with their original node values.
I have a list of items normalized in database. Then in details page, I want extra attrs from the selected item, what is a good approach to this ?
@nxqd: something like [{:list [:foo :bar]} {:detail [:foo :bar :baz :else]}]
?
@iwankaramazow: what I would like to know is, when I load the list pages, I have a list of normalized items only have [:foo :bar]
. But then in details page, I want more, so I would load more attrs for a particular item in those normalized items already in state. So in this case, should we do another query to backend to get more attrs, then merge it manually, or do some sort of mutation ?
This is a read, nothing gets mutated here. You'll have to diff the keys that are available on the client. The ones that aren't make it to the remote
true I have tried the same approach. I think I miss something here. This is what I tried:
create a read like this :project/get
I check if the one I get in state has the same keys I request or not, if not I send it to remote.
I think I should do 1 more step to merge the result returned to current state ? or will it be automatically merged ?
The remote read should be merged in automatically. If the remote results arrives, does your app state contain the extra keys?
Or doesn't it re-render?
can you show me some code from your parser?
(defmethod read :project/get
[{:keys [parser target query state ast] :as env} k {:keys [id] :as params}]
;; if we have id then we want details project/by-id which have more attrs
(let [st @state]
(if id
(let [val (get-in st [:project/by-id (uuid id)])
ks (into [] (keys val))]
(if (or (nil? val) (not= ks query))
{:remote true}
{:value val})))))
I think you have to return a remote and a value together.
{:remote true :value val}
any luck?
hmm, I'll cook up an example. Give me an hour 😄
hmm, I can see that there is value being merged here, but in the code above, id now is nil so it doesn't go throw and return the new value. The problem might be, the read function is being reread but the params is not persisted.
ah indeed
What if you change the read to [{[:project/get some-id] [:foo :bar :bas]}]
ids should probably go straight into the query as an ident
I change to
`[{[:project/get ~'?id] ~form-query}]`
but there is error regarding the query ( long error stack ) http://i.imgur.com/zDKFwZz.png[{[:project/get id] ~form-query}]
?
I'll try writing an example
hmm, I just found out that the problem occurred when I change the params with (om/set-query!)
the re-read doesn't happen?
when I use set-query! to chane the id to the the correct one, the error I posted above happens.
om/db->tree can handle idents I thought
yeah, hmm but only get the ~form-query in query variable in read function. How can I get the whole thing :-? including the id. Ah ok I got it, let's see, it's a bit complicated T_T
yea it's a bit more complicated than I thought 😄
I'm trying it out
we only have :project/by-id
normalized in our db. :project/get
is just a function we use to get more attrs,
I see some people try to persist some value into the state like :project/get-id 123, then they get it back when the result returned. It would be a solution but it's a bit hacky.
I thought of that, it should be possible with params only
Might take me some time to figure it out 100%
@iwankaramazow: Have I got an example for you! https://github.com/Peeja/om-next-starter/blob/list-noodling/src/om_starter/core.cljs
I'm not entirely following what's failing for you, but that may provide a reference to see what you're missing
@peeja: thanks, but I just finished a similar example 😄
@peeja: interesting case of using multiple but if we have multiple details page, we will end up with multiple remotes as well ?
@iwankaramazow: have you figured something out ? I'm really out of idea xD
@nxqd: Yea I've got it working 😄 just posting it to github gist, a second
@iwankaramazow: Well, you'll end up with a remote for every API endpoint. In the case I'm abstracting, there was already a single list endpoint that had a few attributes on each item, and another endpoint with more attributes for a single item.
@iwankaramazow: Glad it's working! Looking forward to seeing what you did.
will take me 10 more minutes, I forget the query diffing
@peeja: aha, actually we can replace multiple remotes with a read, it would work the same.
@nxqd: this is a minimal example without query diffing https://gist.github.com/IwanKaramazow/127bb8f47a823c2a36595bf54156f976
if you run it, you'll see :title
in the list and :title :description
in the selected detail
nice, good fake db though, it makes much easier to make short example. I will check it, it seems to be the same approach I took but the id seems to be persist
fixed a syntax problem in the gist
@iwankaramazow: yeah it works flawlessly, I think there is something wrong with my code that the id is changed to nil when it being reread.
@nxqd: just finished the example with query-diffing 😄
@iwankaramazow: nice 😄
It'll only fetch :description
if :title
is available in the app-state.
Om Next is just awesome 😄
hmm, I still wonder how come the id in mine returned nil after the new value being merged to om next db
@nxqd: the id in your app-state is nil?
does it get updated in the meantime? something that resets it ?
don't forget to return the id from your backend
I wrote about routing once again 🙂 https://twitter.com/anmonteiro90/status/742064369744367617
TL;DR: this is the solution I talk about in my post, a library I made available just now https://github.com/anmonteiro/compassus
@anmonteiro: Great work! Does this support nested routing?
@iwankaramazow: be clearer 🙂
You have an App component that needs to be displayed on every page. App contains a query. Inside App you want to render the specific pages, let's say About page on /about and Profile page /profile. The both contain another query. How should I implement this with compassus?
(def routes-in-pseudocode
{"/" {:component App
:children {"about" {:component About} "profile" {:component Profile}}}
so the common component that’s displayed in every page you specify via a :wrapper
key to compassus.core/applicatioN
your route declaration would then be
{:about About
:profile Profile}
URL/ path navigation is a completely different concern
for which there’s support, of course, but a different concern nonetheless
the README goes into this here: https://github.com/anmonteiro/compassus#integrating-with-browser-history
Aside from the path/url nav, should it be possible to use a :wrapper
on arbitrary levels?
if profile for example is another container for two children
or am I stretching things here?
the possibility to supply a wrapper on the top level is for the sole reason that Compassus will create the root component for you
@iwankaramazow: if you want a “wrapper” at the profile level, there’s nothing stopping you from doing that, but you don’t need to hook into Compassus to do that!
Ok, I think I got it 🙂 Thanks!
@iwankaramazow: something else that I want to be clear about: “nested” routing as in /item/42/owner/43/edit
is something that is not included by design
it is my understanding that routing is a top-level concern (read the Disclaimer in my post)
everything else you should be doing in the app-state
e.g. specify the same handler for arbitrarily nested routes, deal with the params in the app-state
hope this is clear
happy to be more specific about this in the README if you feel the information is missing
It's perfectly clear 🙂
The design is very sound
Yeah, it’s been brewing for a while
It’s also a goal to keep the API surface very small
Om should have every function you need except from the ones that I provide
Really great job on this
@anmonteiro: Compassus looks good! I'm currently using one Bidi route + multiple tags to differentiate some different page contents using the same Page component, like so:
(def routes
["/" [["landing" (tag :route/page :page/landing)]
["privacy" (tag :route/page :page/privacy)]]])
Could this work with Compassus some how? Or would you suggest instead using unique route names and directing them to the same component like (compassus/application {:routes {:landing Page :privacy Page}})
? This will multiply my parse functions.@thosmos: the problem that Compassus tries to solve is routing to components that have different queries
if your matches always route to the same component, how are you managing queries?
Most of my routes are different queries, but some of them aren't as in this case of generic pages. Currently my pushy handler converts the tag into a query param on the routed component's static query and then adds that to the static root component's query (I think you call this the "wrapper") and then does a (set-query! reconciler {:query root-query}) The handler does this for every route change.
@thosmos: I think Compassus can definitely support bidi’s tagged matches, but definitely not a set-query!
approach
@thosmos: the problem would be that the two approaches are conflicting
so it would seem that if you’re going to move to compassus, you’d have to re-engineer some part of your system
what I’ve found in my projects is that my Root component just becomes the :wrapper
would the wrapper component be able to change based on the route? i.e. if there's a nav bar in the wrapper it can change to show the current page?
re: tags multiplying parsing functions, you can always use another form of dispatching other than om.next/dispatch
that would be the answer, yes
current-route
is also pretty flexible in the sense that it allows you to pass a component, reconciler or CompassusApplication
instance
set-route!
too
you can call it from whatever component, even from components that don’t implement IQuery
(even though it call transact!
under the hood)
@thosmos: do let me know if anything is not clear. I’m happy to re-write the docs to make them clearer
as well as rethink some of the API stuff that doesn’t reveal flexible enough
thanks, @anmonteiro looks good. I'll probably try it out on my next om.next app
sounds good! looking forward to hearing feedback