This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-08-15
Channels
- # architecture (2)
- # beginners (16)
- # boot (2)
- # cider (4)
- # clara (6)
- # cljs-dev (78)
- # cljsrn (3)
- # clojure (158)
- # clojure-austin (1)
- # clojure-belgium (1)
- # clojure-dusseldorf (19)
- # clojure-italy (8)
- # clojure-russia (3)
- # clojure-spec (77)
- # clojure-uk (61)
- # clojurescript (341)
- # cursive (9)
- # data-science (12)
- # datomic (18)
- # emacs (9)
- # fulcro (109)
- # hoplon (10)
- # juxt (2)
- # leiningen (2)
- # lumo (31)
- # off-topic (1)
- # om (4)
- # onyx (40)
- # parinfer (17)
- # re-frame (36)
- # reagent (19)
- # spacemacs (10)
- # vim (60)
- # yada (20)
@tony.kay if i wanted to wrap the parser functions, how would i do that?
used to be you could pass in the parser into make-untangled-server
:parser (om/parser {:read api/parser-read
:mutate api/parser-mutate})
i basically have some parser “middleware” that i want to execute on every parser read/write
@currentoor oh, do you mean you’d like to use defquery and defmutation as well? There are multimethods. Wrap those with your own functions, make a parser, and pass it in.
actually, there is one multimethod for mutations (fulcro.server/server-mutate) and server-read is a function that dispatches to two diff multimethods
so, just make a parser by wrapping those (om/parser {:read (fn [env k p] … (server-read env k p)) …
@tony.kay how about with the not easy server?
same thing. There it is more obvious, because you have to make a module that dispatches
fulcro.server/fulcro-system
just wrap the predefined server-read and server-mutate with your own fns, and supply those to the module
or you can not use the provided ones at all…doesn’t matter. They’re just for convenience
oh perfect
thanks!
Yeah, I was just adding some convenience macros for writing queries and mutates on the server, but if you don’t want to use those, nothing is different at all. They were adds, not changes
Just released Fulcro 1.0.0-beta8
Remember that if you use spec, you must use at least beta7
is there a better way than "om-computed" for doing listing with odd rows highlighted differently ? 🙂
@claudiu CSS even/odd rules might help if you’re just after highlighting. If you need different behavior based on index, computed
is probably your best bet short of setting something like :ui/index
on each element in a mutation.
@gardnervickers cool 10x, totally forgot about css rules (been a while since I wrote css). 🙂
computed it is, since I might have the case of same component in two listings ui/index would override each other
also remember you can always make your factory do the computed part for you for a bit of syntactic sugar: (defn ui-row [props & {:keys [highlight]}] ((om/factory Row) (om/computed props {:highlight highlight})))
-> (ui-row row :highlight (odd? idx))
(I actually tend to let
the factory around the defn for a bit more efficiency…but the concept is the same)
(let [f (om/factory Row {:keyfn :db/id})]
(defn ui-row [props & {:keys [highlight]}]
(f (om/computed props {:highlight highlight}))))
don't know exactly how this works. Is there any difference between adding the defn outside of defui or in the render
let ? (wondering if functions will be recreated when the component updates)
you don’t want to re-run defn within the body of a function, unless you actually want to be able to dynamically change that code over and over
It is a dynamic language. If you re-run a defn, it redefines the function. At the file-level, everything is evaluated on load. Mostly you do non-side-effecty things (like define functions)…but you can also just run whatever code you want. Remember that while def
and such might be special forms or macros, then are still just forms, and the language itself is perfectly happy to run those forms where/when it finds them.
The problem with running a defn
inside of something that has not run yet should be obvious: the function won’t be defined until that thing runs. This leads to your program changing over time in a way that is more path-dependent than most people prefer…for good reason
was a bit confused by the (let
don't remember seeing it in the top level so far 🙂 but makes total sense, no need for f to be module level. 🙂
Yeah, the let at the top level is surprising to most of us that come from languages with tons of “syntax”. It’s funny how a langauge with almost no syntax leads to such surprises…the syntax fits on a single page: put forms in a file 🙂
i thought i had closures all figured out, but i would've never thought of using them like that!
ahh yes I meant namespace. Yep pretty much, every day amazed by clojure. Now that I'm actually building a production project, it's even more impressive. A ton of small things like this and declare
, that are really nice.
I am kind of fond of it, actually. Better than “private”. Completely isolates the definition to a one-time run, and a very local scope.
awesome book 👆
So I used to have something like
(f/load-data reconciler [{:dashboards (om/get-query DashboardTableRow)}
{:reports (om/get-query Report)}
{:current-user (om/get-query User)}]
:post-mutation 'post-initial-load)
But since we don’t have load-data
anymore, how should I go about doing this? Make a new root query that includes all three of these?or a component that queries for these three?
joined
No, three calls to load, with the post-mutation on the last one (or the one it most relates to)
networking cannot go until you release the thread…so multiple calls to load can issue a single net req
oh wow that’s cool
thanks @tony.kay !
it makes the load story cleaner…the post mutation might be needed on a sepcific bit, and this makes it more obvious…also targeting with :target
can avoid many post mutations, but can only apply to one graph edge of the load…so it just makes it much simpler.
makes sense
I’m glad to see that your initial loads mapped over so cleanly. I was hoping that was the kind of thing people were doing with load-data
.
yeah that sounds like a headache
The network layer is joining queries if they don’t have the same root key? I was under the impression that
[{[:person/by-id <>] [:person/id :person/name]}
{[:person/by-id <>] [:person/id :person/age]}
Would result in
[{[:person/by-id <>] [:person/id :person/name :person/age]}]
Is that not the case?I think @jasonjckn did that patch….Jason, do you remember?
Ah yes I guess it would only really make sense if it was for queries rooted at an ident
I know it tries to do “the right thing”. Remember the response is a map, so only one key per response is possible.
Ah hm I might have been confused seeing this in vanilla Om.next, but now I’m interested if Fulcro does anything like this?https://github.com/omcljs/om/blob/master/src/test/om/next/tests.cljc#L1805
Besides what you mentioned above, on non-ident keys.
as process-roots eliminates “roots”, you can end up with queries that collide on the outgoing side
So for the routing example, you could re-root your query at the level of each page?
Yea, if using a union routing solution like Fulcro has
Versus Fulcro having you do a data load on the component?
well, in general, in Om Next, the remote queries always end up going to the netowkring with path all the way from root…so process-roots lets you strip off (and re-add) the stuff the server doesn’t want to see.
in Fulcro, you write the query from the component that is actually persistent…so there is nothing to strip
Om Next: ui-rooted == process-roots ==> server query ==> server-response ==> process-roots ==> ui-response ==> merge
Fulcro: query => server => response => merge (optional move when using :target, or post-mutation to alter UI tree based on result)
Ah thank you that helps my understanding quite a bit.
Ahh yea the post mutations and use of :target
end up replacing process-roots
response rewriting then?
Not to mention that in Om Next you have to write a parser emitter to actually even get the remote query. It is just peppered everywhere: parser logic, process roots in network logic, helpers in merge logic….
Yes. The targeting lets you put the result where you need it…but since things are normalized, that isn’t so bad (3-levels deep, max)
it’s one more advantage to picking the db format. In Om Next (pre-decisions on various configurable things) you can’t do it. The pluggable database keeps you from pre-writing the logic.
Ok that made it click for me, forgot about the restrictions not knowing the DB format imposes.
well, the parser is also a big wrench in the cogs…even with a db format, there’s nothing to say how you convert to-from the db because the parser is unknown logic
The concepts are all great (which is why I’m basing off of it), but wow is it somewhat impractical to build a real app on top of without a lot of base work that has little to do with your app
Yea the parser is insanely hard to write without some well thought out conventions about recursive db access, although we’ve been slowly locking down those patterns and using Fulcro’s local reads to implement keys representing a projection of app state. Some of our computations were difficult to keep up to date with mutations and much better suited as derived views.
Having :read-local
has been a pretty great escape hatch for us.
@gardnervickers oh,you mean the new support for hacking into the parser???
Heh yea
How’s performance when recomputing those every UI refresh? Or are you also doing some other kind of caching?
We actually need to recompute them every keystroke, but we’re running them either in a webworker or in a core.async go-loop so they kinda naturally end up cached in a channel for us.
Yea! David and I worked through two bugs with code-splitting. The cljs compiler at the tip of master works now 🙂 So, dynamic (auto-loading code-split screens) router and dynamically loading i18n locales will soon be solid features!
Fantastic!