This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-08-17
Channels
- # announcements (8)
- # atom-editor (8)
- # aws (1)
- # babashka (96)
- # beginners (128)
- # calva (7)
- # cider (12)
- # cljsrn (1)
- # clojure (75)
- # clojure-europe (28)
- # clojure-hamburg (2)
- # clojure-italy (7)
- # clojure-nl (7)
- # clojure-norway (3)
- # clojure-uk (13)
- # clojurescript (26)
- # conjure (2)
- # cursive (18)
- # data-science (7)
- # datalog (21)
- # datomic (9)
- # duct (15)
- # expound (29)
- # figwheel-main (14)
- # fulcro (59)
- # helix (4)
- # jobs (2)
- # kaocha (19)
- # leiningen (15)
- # luminus (4)
- # malli (57)
- # meander (2)
- # off-topic (2)
- # pathom (12)
- # pedestal (8)
- # re-frame (53)
- # reitit (9)
- # remote-jobs (1)
- # shadow-cljs (64)
- # spacemacs (1)
- # specter (2)
- # tools-deps (12)
- # tree-sitter (2)
- # vim (11)
- # xtdb (17)
Anyone have advice for using client state such as current-user in an RAD form (`defsc-form`)? Lets say I have an entity Item with attribute item/owner that I want to automatically set to the logged in user when the form is saved - I tried messing with fo/query-inclusion
but couldn’t seem to get anything added to the form’s query.
Or is the right way to do this to handle this with save-middleware
?
Isn't it kind of expensive to generate an uuid for every transaction ? Does it mean that heavy local mutations (say, complex animations) would be better served by swap!
ing on the state atom and manually scheduling a render ?
@adam678 there are all sorts of things you’d do in a complex animation…i.e. you’d probably use component local state, not an async transaction. Fulcro is about full-stack data model, not gaming.
I worked on a prototype of something using three.js where I wrote a separate reconciler (three controls a canvas) for sync’ing data model with UI…Fulcro was used for doing the forms and full-stack data interactions, and loading a normalized data model representing the objects in the scene, but was not involved in the 3d rendering. You do what is right for the project in question. No tool can solve all problems.
@tony.kay Yep, right tool for the right problem. It's just I am still wrapping my head around the API. I am recording data (let's say 20 updates per second), this data figures both in a rather complex canvas animation and part of it is in the DOM as well... Somewhat non-trivial, I am trying to figure out how to organize this. Thank you for your fast answers, I will probably hang out here for a little while yet! And thank you for building all this, it is quite a beast.
Right. Fulcro is very pluggable. You can replace the tx processing system, the rendering routine…hell, you could make it render via ncurses on a UNIX ascii terminal on a 300 baud modem if you really wanted to (i.e. no React).
Some of the bits are there to make reasoning in a distributed system a bit easier…and some are legacy compatibility
@tony.kay Any chance you could put an example of adding a new type that isn't derived automatically to the fulcro-rad-demo? Or add some documentation? I am trying to create a couple new types for :url and :link (for counting clicks) but I am not very good with clojure yet so I am not making much headway. A simple example would probably give me enough to build on. Awesome project, thanks so much for creating it. I am really liking how simple it can be to iterate on app ideas.
@michael819 did you look at the fulcro-rad-semantic-ui source? the all_controls namespace…also, I thought the demo had something…what do you mean by adding a new type? You mean full-stack db-wise? I would do URL and LINK as renderers of a string type.
hm…guess not…here’s a sample from my prod app:
(rad-app/install-ui-controls! @app-atom
(-> rad-sui/all-controls
(assoc-in [:com.fulcrologic.rad.control/type->style->control :instant :starting-date] date-controls/midnight-on-date-control)
(assoc-in [:com.fulcrologic.rad.control/type->style->control :instant :ending-date] date-controls/midnight-next-date-control)
(assoc-in [:com.fulcrologic.rad.control/type->style->control :date-range :default] date-controls/date-range-control)
(assoc-in [::form/type->style->control :string :ucv/ssn] render-ssn-field)
(assoc-in [::form/type->style->control :string :ucv/tysys-account-credential] render-tysys-account-credential-field)
(assoc-in [::form/type->style->control :string :ucv/phone-number] render-phone-number-field)
(assoc-in [::form/type->style->control :string :ucv/color] render-color-field)
(update-in [::form/type->style->control :decimal] merge {:USD rad-numerics/render-currency-field
:ucv/percentage rad-numerics/render-percent-field})))
so something like (assoc-in [::form/type->style->control :string :your-ns/link] render-link)
would be for a form control that can edit links
see rad-sui/all-controls for the different spots you can add stuff in the SUI render plugin
@tony.kay I see it now, I did not look in the fulcro-rad-semantic-ui repo. It looks like the namespace is com.fulcrologic.rad.rendering.semantic-ui.semantic-ui-controls
RAD itself does not define how a renderer works…so that will always be render-plugin-specific, though RAD does define the concept of styles…but still it’s all open maps, so a plugin could easily veer off that path
well, I guess there are some “entry point” definitions in there for getting to the renderer…just saying, the nested structure is amenable
@tony.kay Thanks again for a great product, I hope to get good enough I can contribute. This is exactly what I needed to create what I had in mind.
It is a lot more fun to work with the higher-level data than do all the low-level messing around all the time.
I've been following along with a series of blog posts on using Fulcro and for authentication they needed to add an asynchronously fetched value to the headers that their remote always sends.
They basically ended up solving the problem by copying wrap-fulcro-request
and updating it to use a go block inside of the returned function and then copying fulcro-http-remote
and using a go block inside of the transmit!
function too.
I was wondering if there was a more idiomatic way to do something asynchronously in a remote's middleware?
For reference, blog post can be found here: https://chrisodonnell.dev/posts/giftlist/api_auth/
unfortunately no. My assumption when I designed that was that async stuff would happen outside of the middleware (e.g. you’d do auth, a cookie would get set, and you’d just “have it” by the time middleware was involved). Same with token exchanges…seems like putting the value in a top-level atom and just accessing it from middleware is sufficient. You either have it or you don’t; however, if you’re trying to do something where the middleware itself makes some kind of side-band async request all bets are off for prebuilt stuff…I mean, you could copy the source of the existing remote and augment it with core async and expect middleware to return channels…but I’m not interested.
it would be trivial for someone to make an OOS remote for Fulcro that adds extra features…after all, a remote is just a map
When I want to return 2 components after a mutation I do that
(defsc MergeReturn [_ _]
{:query [{:>/a (comp/get-query A)}
{:>/b (comp/get-query B)}]})
(m/defmutation operation
[_]
(remote [env] (m/returning env MergeReturn)))
This MergeReturn
still a valid solution or there is a better way to do that?To anyone using Fulcro Spec test helpers: I just release 3.1.6, which improves: • Mocking errors. Recently that had regressed to just say ExceptionInfo, which was worse than useless. Now reports the exact nature of the mocking failure. • Exception stack traces: Are not printed inline with the test failure, and are filtered/pruned according to two dynamic vars you can control (for terminal reporter in CLJ/REPL). See https://github.com/fulcrologic/fulcro-spec/blob/develop/docs/index.adoc#controlling-stack-trace-output
The RAD book states: “The subforms themselves can act as standalone forms, but will not be running their own state machine unless you route directly to them.”
However, When I try to route to a form that is a subform of another via form/create! this MySubForm
, it takes me to the parent form (I guess this isn’t routing directly to it :man-shrugging: ) — anyone know how to route directly to one?
Im trying to create the ability to create nested relations, but edit a specific subcomponent. For example, if an Account has many Portfolios, which has Many Projects, I want to be able to add new portfolios from an account form, but if I want to edit a Portfolio, I want to be able to zoom into a PortfolioForm
I can do this with separate forms fwiw
So you can create one that way, but how do you expect it to be “linked” to the parent??? Not sure why routing is not working for it, unless you didn’t give it a route prefix.
At the moment, RAD, by itself, cannot handle you creating some child outside of a parent context. To do that you’d have to probably support some virtual reverse reference attribute that could stand for the parent’s ID, and fix that up on save in save middleware on the server.
e.g. :portfolio/account
which is not reified in DB, but which is an attribute on the form, which in turn you pass in as an argument to create’s :initial-state
One thing I noticed about setting :initial-state
is this becomes a "before" value in the delta saved to the db.
for non-to-many fields, this is fine, as to-one-txn
, as if there is a non-nil after
in the delta, it will be used directly
however in to-many-txn
, we look at the set/difference
of the before and after and save that, so I guess its dangerous to use :initial-state
for default values of to-many fields? Or am I misreading the logic
I’ve lost context…so no idea what you’re getting at. To-many in initial state works fine in normal apps. If you’re doing something strange, then, well, you have to figure it out
the original context was setting default values for a new form It seems that if you set initial state on a from.create for a to-many field, it will be filtered out before saving to the db. Will figure out a workaround
*default values set from context from outside the form (i.e. the component that triggers the form.create!)
use UISM to control form logic flow. pre-merge
is a reasonable broad-stroke way to do it as well
initial state is about exactly one thing: The initial value your app state will contain for the very first animation frame displayed by your app on mount.
Full stack operation is a sequence of follow-on operations. The only form that you might pre-configure in initial state would be something like a login form, where it isn’t really a full-stack persisted thing…it’s just a form…but in that case, you don’t really need fs support, since there’s never a need to undo/save. Maybe a “Contact Us” page? Yeah, initial state for forms is mostly an anti-pattern.
forms have a lifecycle, and at certain predictable times, they are initialized/loaded/saved
but initialized with what: content from server, new content, etc. More than one possible entry to “initial”
got it, makes sense, thanks for the response
Then when you save, add in save middleware that would look for that attribute and fix up account to point to that new (or existing) portfolio
and if you want edit to work, you’ll have to add a resolver that can “figure out” :portfolio/account
when given a portfolio id
Got it — I’m trying to figure out how to handle forms with “implicit” fields with fixed values set from previous context — for example, I want to create a “New Portolfio” form that allows you to create a new portfolio for your user — my best way of doing this with RAD is to create a form on the account layer, have the only field to be edited be :account/portfolios
I originally tried to have a reified :portfolio/account
field, instead of :account/portfolios
but I couldn’t figure out how to pass this to the form (asked about this above https://clojurians.slack.com/archives/C68M60S4F/p1597641494045800)
> e.g. `:portfolio/account` which is not reified in DB, but which is an attribute on the form, which in turn you pass in as an argument to create’s `:initial-state` (edited)
Ah that makes sense, it could be a non-reified attribute that I pull up.. If I did that, then my :portfolio/account
approach would probably be viable
(form/defsc-form AccountPortfolioForm [this props]
{fo/id account/id
fo/attributes [account/portfolios]
fo/route-prefix "account-portfolios"
fo/title "Edit Portfolios"
fo/subforms {:account/portfolios {fo/ui PortfolioForm
fo/title "Portfolios"
fo/can-delete? (fn [_ _] true)
fo/can-add? (fn [_ _] true)
}}
Thats one way I was achieving this sort of view
> Not sure why routing is not working for it, unless you didn’t give it a route prefix.
The routing would take me to /account/create/<new-temp-id>/portfolios/create/<new-temp-id>
My expectation was it’d take me to /portfolios/create/<new-temp-id>
and when you call form/create
did you pass it Portfolio? Was the route prefix unique?
You can pass :initial-state
in the options to form create to pass in default values for something you’re making that is new
> but did you give Portfolio it’s own `fo/route-prefix`?
yeah, that’s how Fuclro is somehow appending /portfolios/
(or whatever I change the route-prefix to) in the route
> and when you call `form/create` did you pass it Portfolio? Was the route prefix unique?
(ui-dropdown-item {:onClick (fn [] (form/create! this PortfolioForm ))} "New")
Yeah, i changed the route-prefix, and it links to the subform route param /account/create/<new-temp-id>/<whatever route-prefix-i-choose>/create/
Its not blocking me, as I can create a shared options map and pass that to to a new form with a unique symbol / route-prefix, was just curious if I was doing something obviously wrong.Did you add the Portfolio thing to the ROUTER? Otherwise it is always a child of the account
routing is a recursive search…if it isn’t at the routing layer you want, then it will end up in a nested route 😜
D.R. should probably give a warning for that, since there is no router in-between, so the routing isn’t actually going to work right when you do that
yeah, its in the router