If I want to swap! an atom on a button click, all client side and with no need for error handling, am I still supposed to use e/Token? Or is it OK to just do the swap! in the "event transforming function" passed to dom/On?
And is it safe to do in the context of a virtual scroll? For example, the following seems to work fine. Am I setting myself up for trouble?
(ns electric-starter-app.main
(:require #?(:clj [electric-starter-app.debug :refer [pprint-str]])
[hyperfiddle.electric3 :as e]
[hyperfiddle.electric-dom3 :as dom]
[hyperfiddle.electric-forms5 :as form]))
(defn px [n]
(str n "px"))
(def row-height 24)
(e/defn Table [items Row]
(dom/div
(dom/style (dom/text form/css))
(dom/props {:style {:height (px (* row-height (count items))
:--column-count 1}})
(form/VirtualScroll :table :tr row-height 1 items Row)))
(e/defn ClientRow [!selection _index {:keys [id label]}]
(e/client
(dom/On "click" #(do
(println "ID:" id)
(swap! !selection conj id) nil) nil)
(dom/td (dom/text label))))
(e/defn Main [ring-request]
(e/client
(binding [dom/node js/document.body
e/http-request (e/server ring-request)]
; mandatory wrapper div
(dom/div (dom/props {:style {:display "contents"}})
(let [options [{:id 1 :label "One"} {:id 2 :label "Two"} {:id 3 :label "Three"}]
!selection (atom #{}) selection (e/watch !selection)]
(Table options (e/Partial ClientRow !selection))
(dom/button (dom/text "Reset")
(dom/On "click" #(do (reset! !selection #{}) nil) nil))
(dom/div (dom/text "Selection:" (pr-str selection)))))))) yes, token is unnecessary for safe synchronous updates as there is no pending/retry state. Here is a client-only counter:
(dom/button (dom/On "click" (partial (fn [!n e] (swap! !n inc)) (atom 0)) 0))in the virtual scroll case, as long as your atom is outside the scroll, which it is, this is fine
indentation - if you are using cursive, alt-enter to configure indentation for container macros
Is it idiomatic for an electric function to take a map as an argument and destructure its fields? Or does that harm the granularity of reactivity in any way?
I remember something about e/amb being preferred when passing multiple form values over passing them in a map for this reason, but I can't find the place in the tutorials where this is said (maybe this was only explained in Dustin's latest talk?)
My guess would be that on any map update Electric will have to compare the new values of all destructured vars to the old ones (which would not be necessary if they had been passed as separate arguments), but after that it will work skip if it finds they have not changed?
So, not terrible but better not to do it
I asked about this early in v3, but I think it was before all the amb docs were out. https://clojurians.slack.com/archives/C7Q9GSHFV/p1724137072396609?thread_ts=1724007358.949779&cid=C7Q9GSHFV I think it might be fine if the contents are all on client or server. I am currently passing server-side deps in a map to my client entrypoint and seems to work fine if I only access them from the server. If you want to use something on the client I think you'd need to destructure/get the value on the server and only reference that in a client block
it depends, but definitely pass perf-sensitive objects as an explicit parameter. perf sensitive can mean - values that update frequently, values that are sensitive to accidental transfer, any kind of collection. Note that you cannot store electric tables (`e/amb`) inside clojure data structures, it implies a product. so basically - be careful.
Thanks to both! In my case I didn't have a particularly good reason to want map params, so I'll just avoid it
Could you add a tfoot element to dom3? I tried to add it myself but com.hyperfiddle/electric-secret {:local/root "../electric-secret"} stopped me.
yes and you can add it in a userland ns for now as well
Will do, sorry for posting in a thread. I didn't notice 🤦♂️