Fork me on GitHub
#fulcro
<
2021-07-28
>
genekim04:07:00

Thanks for the help today, @tony.kay — I’ve got Dropdown selection box going, loaded with data from resolver. How do I actually get the result from the dropdown out? Is there an :onSelect I can hook into, or a way to get the current value from the DropdownTest or MoveModal component? Code current reads:

(comp/defsc DropdownTest [_ {:dropdown-options/keys [move-targets]}]
  {:query [:dropdown-options/move-targets]
   :ident (fn [x] [:component/id ::MoveDropDown])
   :initial-state {:dropdown-options/move-targets []}
   :componentDidMount (fn [this]
                        (df/load-field! this :dropdown-options/move-targets
                          {:parallel true}))}

  (rcomp/ui-wrapped-dropdown
    {:multiple false
     :options move-targets}))
     ;:onSelect #(fn [e] (println "DropdownTest: select!"))}))

(comp/defsc MoveModal
  [this {:ui/keys [card-id dropdown visible?]
         :as props}]
  {:query         [:ui/card-id
                   :ui/visible?
                   {:ui/dropdown (comp/get-query DropdownTest)}]
   :initial-state (fn [x] {:ui/visible? false
                           :ui/dropdown (comp/get-initial-state DropdownTest)})
   :ident         (fn [] [:component/id ::MoveModal])}
  #?(:cljs
     (do
       (println "MoveModal: visible?" visible?)
       (ui-modal {:open (boolean visible?) :dimmer true}
         (ui-modal-header {} "Move Card")
         (ui-modal-content {}
           (dropdown-ui dropdown))
         (dom/button :.ui.button
           {:onClick
            #(comp/transact! this [(toggle-modal {})])}
           "OK")))))

Jakub Holý (HolyJak)11:07:53

Unrelated, but any reason you use lambda ins3of the simpler and error checked template init state?

genekim16:07:24

I don’t really know: when I do this (or try to make it a vector of maps):

:initial-state {:ui/visible? false
                :ui/dropdown (comp/get-initial-state DropdownTest)}
I get an error:
Encountered error when macroexpanding com.fulcrologic.fulcro.components/defsc.
defsc MoveModal: Illegal parameters to :initial-state (comp/get-initial-state DropdownTest). Use a lambda if you want to write code for initial state. Template mode for initial state requires simple maps (or vectors of maps) as parameters to children. See Developer's Guide. at line 85 com/example/ui/trello_main.cljc
-

tony.kay19:07:10

The non-fn initial state calls get-initial-state for you, and only needs params...`{:ui/dropdown {} :ui/visible? false}` is all you need to get exactly what you have.

Jakub Holý (HolyJak)20:07:47

Tips or PRs for making the error message more helpful / clearer are, I am sure, appreciated 🙂

tony.kay04:07:29

the ui-wrapped-dropdown has those, which are really supplied by the low-level ui-dropdown from SUI. I think it is onChange

genekim17:07:02

Yep, I saw that, but still having trouble getting it working — my onChange call back not being called, and having trouble getting head around other ways to get value of the component. (was thinking maybe I was supposed to put it into the query… or something?)

(rcomp/ui-wrapped-dropdown
    {:multiple false
     :options move-targets
     :onChange #(fn [e] (println "DropdownTest: select!")

tony.kay19:07:10

and no # on fn

genekim02:07:32

Doh. Fixed! 🙂 Thanks for help getting this working today!

tony.kay04:07:44

docstring from ui-dropdown should say (within ui-wrapped-dropdown)

tony.kay05:07:34

Fulcro transaction processing has experimental support for batching network reads (unreleased git SHA version). I think I mentioned this some months ago, but don't remember why I never merged it. I think because I have not had the time to test it much in production projects. TL;DR: If you use this support then multiple df/load! calls can be batched together into a single network request, reducing latency. REQURES you use the built-in tx processing, NOT synchronous-tx-processing, or another alternate. I'd be interested in hearing if anyone has luck with it. Here is the lowdown: 1. Use Fulcro git SHA 6a6aecefb7324aaa4e2ade66b24cc1cfe34cc0d0 as your version via deps. I just rebased this off of the latest, so it is 3.5.2 + batched reads. 2. Add the option (app/fulcro-app {batched-reads? true}) to your client-side app. 3. Server-side use the Fulcro middleware handle-api-request (in case you've made a custom one, look at the source of the new one. Basically batched requests come across as a map and return a vector, and non-batched ones come as a vector and return a map. 4. Only Fulcro's http-remote implements the necessary support. If you have a custom network remote, you'd have to make it support raw-body (see the source of http-remote). 5. You MUST NOT override the tx processor on the app. This is only implemented in the default tx processing system. It isn't possible to implement in sync tx processing because that tx processing system tries to do everything, well, synchronously, which means there's no opportunity to "gather up" multiple requests. NOTE: If you don't turn it on (2) and use the http-remote (4), then it will revert to doing normal sequential reads one-request-per-load. If you do the above, then you should see fewer low-level network requests (Inspect will still show them individually, even if they get combined on the network) How it works: Basically I extended the network requests to either be the normal EQL (a vector), OR a {:queries [EQL EQL EQL]}. The latter is new. The server must respond to the latter with a vector of response maps [{} {} {}], one per EQL query. This allows loads to be batched on a single network request, without the possibility for accidental conflicts. The updated handle-api-request just runs each EQL against your processor and gathers the results, so it does not require that you make any server changes at all (if you're using the built-in handle-api-request, and it is trivial to fix a custom one). In order for this to work I had to extend the http-remote to declare if it can handle a raw-body instead of strictly an AST (since the new thing isn't an AST). Only the built-in http-remote currently does this, though it is also trivial to implement. The remote itself simply adds an entry to its definition map declaring it can do so, and then of course implements support for it in the transmit implementation. Final Note: It cannot batch loads that are not queued together. E.g. two different user events issuing separate loads probably will not be combined. This is really mostly effective when you need to issue multiple load! calls all in one functional unit to pull in data for disparate parts of the same "frame" or "feature" of your app.

🎉 11
Jakub Holý (HolyJak)12:07:07

Awesome! Out of curiosity, when Er things queued together / what is one functional unit? I guess 2 loads in client/init would be that or a single onClick that loads N selected things?

nivekuil19:07:56

does this work with post-mutations? I have a system where I issue a bunch of loads then wait for all of them to complete before routing, but have not been able to get it to batch. In general I know you have to get rid of :abort-id and :parallel but not sure what the other constraints are

tony.kay19:07:12

If you mean "does it invoke the post mutations", then yes. It should not change the semantics of Fulcro at all, but instead just reduces the number of network requests to the server.

tony.kay19:07:57

It basically tries to merge send nodes in the transaction layer together, but in a way that looks like each ran in the sequence submitted.

tony.kay19:07:27

So you'll still see N network requests in Fulcro's network tab, but Chrome's network tab will show only one.

tony.kay19:07:26

It has to be that way in order to preserve all functionality. Fulcro has to think that N loads happened and were satisfied...how many network requests that requires is implemented at a lower layer, and is why I was able to do this at all.

nivekuil19:07:31

I'm seeing the {:queries [..]} stuff being sent to the server, but twice with one query in each.. these are df/loads with :post-mutations being issued inside a doseq loop. you do expect these to be batched?

tony.kay19:07:40

it could be that I exempted post-mutations for some reason...

tony.kay19:07:08

(>defn batchable?
  "Returns true when ALL of the ::send-node entries in `to-send` can be batched into an existing batch."
  [to-send]
  [(s/coll-of ::send-node) => boolean?]
  (boolean
    (and
      (seq to-send)
      (not
        (some
          (fn [{::keys [ast options]}]
            (or
              (contains? options ::abort-id)
              (and (map? ast) (= :call (:type ast)))
              (boolean (some #(= :call (:type %)) (:children ast)))))
          to-send)))))

tony.kay19:07:45

looks like mutations and things with an abort ID are the only things exempted...you're not overriding the tx processor in your app are you? (e.g. with synchronous tx processing)

nivekuil19:07:19

ah, you got it. without stx/with-synchronous-transactions there's 1 fewer network call

tony.kay19:07:20

Right...let me edit my original message...I thought I mentioned that