This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-05-04
Channels
- # announcements (25)
- # babashka (7)
- # beginners (52)
- # calva (29)
- # clara (1)
- # clj-kondo (4)
- # cljs-dev (55)
- # clojure (86)
- # clojure-europe (5)
- # clojure-finland (1)
- # clojure-france (1)
- # clojure-italy (1)
- # clojure-nl (1)
- # clojure-uk (57)
- # clojurescript (33)
- # conjure (107)
- # cursive (20)
- # datomic (37)
- # emacs (23)
- # events (13)
- # fulcro (67)
- # helix (73)
- # jobs-discuss (22)
- # lambdaisland (1)
- # leiningen (32)
- # malli (2)
- # meander (9)
- # mid-cities-meetup (1)
- # observability (1)
- # off-topic (14)
- # overtone (3)
- # pathom (39)
- # re-frame (22)
- # reagent (13)
- # reitit (13)
- # shadow-cljs (52)
- # sql (15)
- # tools-deps (29)
- # vim (11)
I can highly recommend guardrails. It feels like i'm living in the future when using them ha
also heavily used in data model layer. I started having lots of fns take a map and destructure the keys they need, which allows you to flow through maps of data without having to pick apart the pieces and then call with positional params. Then spec the maps and get type checking on the keys
@mruzekw guardrails was designed, in particular, for pretty much what core.typed is doing, but using spec: Make it possible to have an opt-in “type system”…but I don’t like instrument
because it always throws. So, guardrails is meant to:
• Be easy to type: it’s just an extra array after arglist, so it doesn’t clutter the normal syntax and can be easily ignored
• Be easy to turn on/off at runtime, so the performance hit can be chosen
• Be possible to tell you about possible problems without throwing exceptions. Often you just wrote the spec wrong…let it run, and fix the spec
• Be possible to elide the specs so they don’t bloat the build! This one is nefarious in cljs. Every spec adds more js to the output. >def
and >defn
, when disabled, emit no code.
dynamic languages, in general, can be very frustrating when you don’t know what the data shape should be. spec can be maddening with the syntax and lack of co-location, and throwing as checks. So, guardrails represents my own personal preference: advisory checks I can turn on while developing, and off during production.
Thanks for that explanation, @tony.kay. Which parts of a fulcro app would you recommend using Guardrails? And would it work on fulcro macros like defcs
?
defsc
checks its own syntax. Remember that macros are compiler extensions, and should be treated that way: They should provide good error messages about the notation that then invent. They also exist in CLJ-land, and if you put a spec on them via fspec CLJ will already treat them as a compile-time check. So, no, there is no need for GR to apply to macros.
The rest of that answer is “wherever possible”. You’ll learn the pros and cons as you go: for example, map?
ends up checking all keys of the map that have specs…which can be very expensive at runtime, and can be annoying for intermediate values (see comments in CLJ community about NOT spec’ing state). It’s too much to ask…I could write a book
updated the RAD book a bit, and put a big marker in where I stopped. The Demo is still the best resource, but trying to keep the book in reasonable shape
I want to test the generated resolvers in the clj repl, is there an example of passing query data structure to the parser
?
(parser {} [:my/key1 :my/key2])
(parser {} {:saless/id 1}) => {[:saless/id 1] #:saless{:id 1}}
:saless/id
is an invalid attribute which does not even exist in datomic, why does it return me the above, and not nil.
@murtaza52 this query is invalid, EQL queries must be vectors
@wilkerlucio is this a valid query (parser {:sales/id 1} [:sales/id])
? Do params from the fulcro are they going to be in the first hash-map, will they be under a specific keyname ?
@murtaza52 it is valid, but not doing what you expect, if you want set a initial context you can do: (parser {::p/entity (atom {:sales/id 1}} [:sales/id])
@wilkerlucio thanks so the params from the UI will be in an atom under the ::p/entity
key
@murtaza52 ::p/entity
is rather an internal pathom thing, UI params are transmitted in the query itself and can be grabbed from there
say, you have (df/load! [:item/id 1] Item {:params {:some-param 1}})
then the transmitted query is [({[:item/id 1] [:item/name]} {:some-param 1})]
and you can grab the params inside the resolver as (-> env :ast :params)
(you can also see what queries are transmitted for any load/mutation in fulcro inspect)
there’s also a distinction between inputs (`:item/id`) and params (`:some-param`), the transmitted inputs are available to the 1st resolver in the 2nd arg. there are cases when you want to propagate inputs/params to the subsequent resolvers, it’s a bit more complicated but fulcro rad repo has it somewhere
here it is
(def query-params-to-env-plugin
"Adds top-level load params to env, so nested parsing layers can see them."
{::p/wrap-parser
(fn [parser]
(fn [env tx]
(let [children (-> tx eql/query->ast :children)
query-params (-> (->> children
(reduce
(fn [qps {:keys [type params] :as x}]
(cond-> qps
(and (not= :call type) (seq params)) (merge params)))
{}))
(dissoc :pathom/context))
env (assoc env :query-params query-params)]
(parser env tx))))})
@fjolne.yngling thanks for the details.
I have defined my schema on the server and am trying to play with the resolvers that were generated by RAD. So given the parser
fn returned by com.fulcrologic.rad.pathom/new-parser
, I want to pass it EQL queries and params.
Based on the above it could either be - (parser {:ast {:params {:sales/id 1}}} [:sales/line-items])
or
(parser {:query-params {:sales/id 1}}} [:sales/line-items])
(based on the query-params-to-env-plugin)
@murtaza52 :sales/id
is not a parameter in EQL terms, it’s an input. the call would be (parser {} [{[:sales/id 1] [:sales/line-items]}])
Just wondering about this, I have a vector in my sim that’s appended to, it essentially internally represents a sort of inventory, so each entity has its own one, however for pathom/fulcro to work well with it, I seem to need to give the items unique id’s? Is this true? Or is there some way that I can generate a dynamic id for them?. I mean I could certainly do something like:
(defn add-inventory-ids [{id :ent/id :as ent}]
(update ent :inventory #(vec (map-indexed (fn [i item] (assoc item :id (str id "-" i))) %))))
(let [ents [{:ent/id 1 :inventory [{:name "an item"} {:name "another item"}]}]]
(mapv add-inventory-ids ents))
I think it should only be necessary to assign a unique id to your inventory items if they're used outside the context of your inventory's :inventory
(aka if they need to be normalized into a table of their own). It should be valid for your :inventory
attribute to have a value of [{:name "Tomatoes"}, {:name "Onions"}]
.
Hmm, I’m just wondering if it causes items to not be refreshed correctly? I keep getting react warnings about not having keys for example…
Normally I see vector indexes being used as keys, but I’m not certain it’s happening here…
That's a separate, non-fulcro issue. If you're rendering a list of react components, you need to assign a unique react key to each component so React knows how to tell which item is which. (Check out https://reactjs.org/docs/lists-and-keys.html#keys for more info.)
The index isn't a great React key, since you can run into issues if you reorder your list items.
Yep, however it worked surprisingly well previously =)… Just wondering what pattern people had for doing that here?
Generally I look for a unique identifying attribute
For example, if the inventory items in your inventory all have unique names, you could use the :name
attribute as the react key.
Which isn’t great in a seq like this, I might have to create some id’s then… or do a uuid?
You could use a uuid if you have to, yeah. 👍
How do you tell the difference between two inventory items with the same name? Is there value in storing them as separate list items rather than something like a tuple ["Tomatoes", 2]
?
They have other attributes that people will want to track, things like purchase price, so they can tell if selling it nets them a “profit”
So two items that are the same, may be treated by the user as being different because they have a different providence…
Sounds to me like it makes sense to assign them an id then!
Multi checklist component exist?
https://github.com/fulcrologic/fulcro/blob/2.8.13/src/main/fulcro/ui/forms.cljc#L1041 There's a checkbox component, a friend asked if there was a multi-checkbox component because he'd like to use multiple boxes at once... so you could check off several options or all of them The closest I can find is the single checkbox
Pardon the terse initial message. (exists? checklist-plural) not a good way to interact with humans xD
@sova Fulcro is generally not interested in providing a UI component library. There was an early attempt at providing bootstrap, but I abandoned that long ago. The React ecosystem is chock full of UI components. Use them. Fulcro provides form state support (you should be using v3, BTW, if you can), which works very well for me in various production apps: but it is interested in helping you manage the persistent state full-stack….not the representation in the UI.
Uh, okay, so there is a checklist component I want to use it like an array, does it make sense just to have a bunch of independent components?
Thanks for the reply. I dig that it's not so UI-heavy, but there is a checklist component and I'm wondering if it makes sense to try and extend this to create a singular component that can have multiple checkboxen, or just use this like a cookie-cutter / stamp.
1. It is not platform independent (form state can be used with Native or DOM), mixing the two was a bad idea. 2. There are tons of UI component libraries…don’t maintain your own (which applies to my library…it isn’t a UI component library, so I won’t maintain one).
My early efforts were misdirected. I have learned from the error of my ways. RAD is the updated approach (where I do provide sample wrappers using semantic UI React components). The library itself does not provide UI components, but makes it very easy for you to use a plugin that is RAD-aware, and extend that. rad-semantic-ui is a sample of such a plugin, but I do not personally plan to round it out any more than I need for my own business uses.
Re RAD, now that you’ve updated the docs, would it be worthwhile reading from there or is it better to look at the demo as a starting point?
Hi, I think that I don't understand some of key concepts of fulcro compoments. because all my components are without initial state and I am getting react errors onchange "com.fulcrologic.fulcro.mutations:244] - ui/toggle requires component to have an ident." This component is a single instance, created from Root
(defsc PerfTest [this {:srv-test/keys [server attach]}]
{:query [:srv-test/server :srv-test/attach]
:ident (fn [] [:component/id ::perf-test])
;:initial-state (fn [params] {:srv-test/server "sisi:25" :srv-test/attach true})
:initial-state {:srv-test/server "sisi:25" :srv-test/attach true}
}
(div :.ui.form {:style {:backgroundColor "#8ee" :padding "1em"}}
(h3 "Performance test")
(div :.field
(dom/label "Attachment")
(dom/input {:type :checkbox
:onChange (fn [] (m/toggle! this :attach))
:checked (boolean attach)}))
(div :.field
(dom/label "Server")
(dom/select {:selected server :onChange (fn [evt] (m/set-string! this :server :event evt))}
(dom/option "localhost:1025")
(dom/option "sisi:25") ))
(button {:onClick #(comp/transact! this [(mm/test-with-email {:server server :attach? attach})])} "Send test email")))
(def ui-perftest (comp/factory PerfTest))
(defsc Root [this props]
; {:query [] }
(ui-perftest)
)
I watched first 5 videos several times, and reread the first 4 chapters, I think that I have a blind spot for something. In your examples you have hierarchy of data model and nested components. My components are global, each with own state Independent from the root., The program I am working it is much more complex than this pieces and it works quite well on the server side. I don't understand the error message: "com.fulcrologic.fulcro.mutations:244] - ui/toggle requires component to have an ident." which ident? Is there a checklist, rules, that must be followed (like no ident on the root component).
Yes, the root component cannot have an ident.
@UQ5QFFX54 the general rules are • compose queries • initialise state • pass props so your example would look like
(defsc PerfTest [this {:srv-test/keys [server attach]}]
{:query [:srv-test/server :srv-test/attach]
:ident (fn [] [:component/id ::perf-test])
:initial-state {:srv-test/server "sisi:25" :srv-test/attach true}}
,,,)
(def ui-perftest (comp/factory PerfTest))
(defsc Root [this {:root/keys [perf-test]}]
{:query [{:root/perf-test (comp/get-query PerfTest)}]
:initial-state {:root/perf-test {}}}
(ui-perftest perf-test))