Fork me on GitHub
#fulcro
<
2018-09-19
>
tony.kay00:09:48

Clearing pending remote requests should clear all queued requests, but there may be a problem in timing

tony.kay00:09:00

You are aware that you can run ptransact within a mutaton?

currentoor00:09:03

oh right so i could conditionally call the last block of muations inside a mutation

tony.kay00:09:27

fallbacks weren’t the best idea…they’re like a mallet when you need a screwdriver

currentoor00:09:36

also while you’re here, is this a bad pattern?

(defmutation handle-failed-payment [params]
  (action [{:keys [state reconciler]}]
    (swap! state assoc-in [:ucv.ui.root.mobile-pos/overlay :singleton]
           {:negative-msg "Payment failed. Please try again."})
    (js/setTimeout #(prim/transact! reconciler `[(remove-overlay)])
                   3000))
  (refresh [env] [:root/overlay]))

currentoor00:09:56

if i want an overlay to show for 3 seconds then go away

tony.kay00:09:58

it’s technically fine

currentoor00:09:37

is there a better way?

tony.kay00:09:09

given that this is way down in nested logic…not that I can think of

tony.kay00:09:51

I discourage transact within mutations for two reasons: 1. People coming from js might make a big mess if they’re in the habit of composing there. If you’re used to nested nested nested callbacks it just seems fine…so I’m trying to encourage better patterns. 2. If you do a transact! within a swap!, things get screwy…because then you’re going to run swaps in swaps and things will break.

tony.kay00:09:27

but technically it is fine to call transact! from within a mutation (not a swap), though I do recommend you defer the nested one (as you have) to ensure that tools and such see a linear sequence instead of nesting

tony.kay00:09:55

e.g. (js/setTimeout #(prim/transact! ...) 0) is fine

currentoor00:09:09

thanks a lot Tony!

kirill.salykin08:09:54

Hi, I am trying to integrate (at least render) [cljsjs/react-tagsinput “3.17.0-0”] from http://cljsjs.github.io/ but w/o any luck I added dependency to the project.clj and have a proper require how I actually render it?

(defn country-input []
  (js/ReactTagsInput.renderInput #js {:value []}))

kirill.salykin08:09:17

do I need to create a factory first?

(def ui-country-inpyt (prim/factory js/ReactTagsInput {}))
?

claudiu08:09:37

If you can, using shadow-cljs for the build might help since you can just use the package from npm (no cljsjs) need.

kirill.salykin08:09:10

thanks, but I think shadow-cljs is not an option

claudiu08:09:37

Haven't tried using js components yet 😞 There is reakit implemented in fulcro incubator https://github.com/fulcrologic/fulcro-incubator/blob/develop/src/fulcro/incubator/ui/reakit.cljs

kirill.salykin08:09:52

> dom/create-element rk/Button #js {:onClick #(js/alert “Pow!“)} “Click me”)))

kirill.salykin08:09:56

i just found the same

kirill.salykin08:09:05

Will try this, thanks!

claudiu08:09:05

you're welcome 🙂

kirill.salykin08:09:26

seems working this way

kirill.salykin08:09:36

(defn country-input []
  (dom/create-element js/ReactTagsInput (clj->js {:value ["GBR"] :onChange #(js/console.log "change")})))

kirill.salykin08:09:55

thanks for help

tony.kay14:09:14

@kirill.salykin you can also use dom/macro-create-element which will give you support for Fulcro-dom-like features. I need to add that to the book, but Wilker’s blog article here https://medium.com/@wilkerlucio/using-any-react-ui-kit-with-fulcro-82cce271b9cc

pvillegas1219:09:14

Using defrouter I would like to add my form data into the precise location for a given router component so that the router rerenders based on that data changing. I’m trying to avoid a root query like {[root/form-name '_] ... } and instead add the form ident in the correct place.

pvillegas1219:09:52

Is this possible? I’m trying to add it into the :page-name table, but it won’t rerender

tony.kay19:09:17

I don’t understand your question, because there isn’t enough context…so that is my only guess

pvillegas1219:09:00

I have this

(defrouter RootRouter :root-router
  (fn [this props] [(:page props) :root-router])
  :integrations-index IntegrationsIndex
  :integration-details IntegrationDetailsHome)
within a child of IntegrationsIndex I’m calling a mutation that does (assoc-in [:integrations-index :form/integration] integration-ident) and
(defsc IntegrationsIndex [this {:keys [page model/by-name form/integration]}]
  {:query [:page
           {:form/integration (prim/get-query IntegrationForm)}
           {:model/by-name (prim/get-query IntegrationList)}]

pvillegas1219:09:34

I tried concocting the path [:integrations-index :form/integration] to rerender the IntegrationsIndex correctly

tony.kay19:09:14

so, I see a few fishy things. Your ident function on your router always returns :root-router as the second element of the ident…but you’re implying that it should be able to be :form/integration

tony.kay19:09:39

so, that will mess up normalization on initial state

tony.kay19:09:05

Then, you’re doing a join on :form/integration in the query of index

tony.kay19:09:21

which would have nothing to do with the ident…but it sounds like maybe you think it should

tony.kay19:09:05

IntegrationsIndex does not have an ident function

pvillegas1219:09:38

does it need one?

tony.kay19:09:49

it does if it is a child of a router

tony.kay19:09:02

and it must return the same thing that the router’s ident function returns for it

tony.kay19:09:46

If you were to use that component with merge-component or a load it would not know how to normalize the data

tony.kay19:09:20

it is optional if you only ever use it as a pre-initialized thing at startup as a child of that one router

tony.kay19:09:28

but to be safe, I recommend one

tony.kay19:09:02

AND, it’s ident is the base of the path where you’ll need to put the actual form ident

pvillegas1219:09:08

Right now I do set initial state to have the right page (which is the only thing I need for routing), but I’ve been hitting this part where I want the router to pass down further information to each child

tony.kay19:09:09

{:integrations-index {:root-router {props of integration index}}
is what your code implies to me

pvillegas1219:09:35

this is correct

tony.kay19:09:24

the router isn’t about passing info

tony.kay19:09:42

The router shows a page and makes a union query (for efficiency)

tony.kay19:09:00

the ident you plug into a router is the only input

pvillegas1219:09:18

What is confusing me is what the relative path of the query for the IntegrationsIndex is

tony.kay19:09:27

You want different instances of that form to show up?

pvillegas1219:09:31

but the ident should solve that

tony.kay19:09:49

You’re already giving it one

pvillegas1219:09:52

I only want one form to show up, but I did not want to make it a root query

tony.kay19:09:00

but you didn’t declare it on that component, just the router

tony.kay19:09:38

(defsc IntegrationsIndex
  {:ident (fn [] [:integrations-index :root-router])
   ...

pvillegas1219:09:48

I’m trying to see what the natural way to model this is, it works if within the query I do {[root/integration '_] (prim/get-query ... )}

tony.kay19:09:08

and the path to place the form ident at is [:integrations-index :root-router :form/integration]

pvillegas1219:09:31

Does it make sense for me to be avoiding putting the form data at the root?

tony.kay19:09:50

Your form component should have an ident function, right?

pvillegas1219:09:15

(defsc IntegrationForm [this {:keys [db/id]}]
  {:query [:db/id :integration/name fs/form-config-join]
   :form-fields #{:integration/name}
   :ident [:integration/by-id :db/id]}
  (dom/div "IntegrationForm"))

tony.kay19:09:18

(assoc-in state-map [:integrations-index :root-router :form/integration] ident-of-form) in a mutation

tony.kay19:09:35

that’s all

tony.kay19:09:53

well, unless you just made up the form and are using form state…then you have a few steps

pvillegas1219:09:13

the above worked!

tony.kay19:09:43

(defmutation new-form [params]
  (action [{:keys [state]}]
    (swap! state (fn [s]
                         (-> s
                             (fs/add-form-config* ...)
                             ...))))

pvillegas1219:09:52

yup, I have that part

tony.kay19:09:58

Yeah, you just need to make the right edges on the graph

tony.kay19:09:15

you named the edge in the query, but you didn’t make it in the db

pvillegas1219:09:01

What is the recommendation on the ident part between the router + children?

pvillegas1219:09:18

talking about (fn [this props] [(:page props) :root-router])

pvillegas1219:09:28

this one is static

tony.kay19:09:31

it has to be consistent

tony.kay19:09:56

but can be as complicated as it needs to be

tony.kay19:09:29

If the router only ever routes to singletons, then what you have is fine

tony.kay19:09:55

But the router can also route to different pages on a given table (e.g. the second element of the ident can vary).

tony.kay19:09:11

The ident determines what renders…no more complicated than that

tony.kay19:09:23

of course, it has to resolve to a real thing in your db

pvillegas1219:09:42

Alright, got it, thanks @tony.kay 👍

pvillegas1219:09:36

Does the defrouter take care of properly setting up the ident for IntegrationsIndex?

tony.kay23:09:12

You should probably watch this video @pvillegas12: https://www.youtube.com/watch?v=HJBI24yAdBQ&amp;index=12&amp;list=PLVi9lDx-4C_Rwb8LUwW4AdjAu-39PHgEE&amp;t=16s In it, I show you how to do UI routing manually. The result is pretty much exactly what defrouter builds. The “short answer” to your question is this: 1. defrouter makes a component whose initial state is the first route listed. It uses the ident function you’ve supplied to look at the props in that to determine what initial ident it is “routing” to. 2. Initial app state understands unions, and will put the initial state of the “other routing legs” into state, it just won’t have anywhere to write idents. defrouter actually generates two things: A component that “holds” the ident pointing to the “current” screen, and a Union Query component (which has no state…it is an interstitial artifact). When you “set a route”, all you’re doing is setting the ident inside of that one real component (the component that holds the current screen ident). Union query of the union element “selects” the subquery based on this ident.

👍 4
tony.kay23:09:28

Thus, some of the requirements are: 1. Every component MUST have an ident (because they have to be merged into state at their proper normalized place, e.g. all but the primary leg are merged via a separate automatic step). 2. The router itself needs an ident function that will produce the correct ident when it is given props from any of the components that stand for the “routes”. This has to do with initial state normalization.