Fork me on GitHub
#re-frame
<
2018-08-28
>
heyarne09:08:15

is there a nice way to pass on the result of a subscription? so i could do stuff like (-> (subscribe [:a]) (subscribe [:b with-result-of-a]) (fn [[a b]] {:a a, :b b}))

valtteri09:08:53

@arne-clojurians to me it sounds like you want to have layer-3 subscriptions https://github.com/Day8/re-frame/blob/master/docs/SubscriptionInfographic.md The idea is that you can compose subs that extract some path from db (layer-2) into a “materialized views” (layer-3).

heyarne09:08:29

yes, kind of. but layer-3 subscriptions seem to work like 1. run some subscription -> 2. do something with the result of the previous computation. the problem i have is that i need a third step (see above, the subscription running with the result of the previous subscription) where i need the result of the first step as well. at the moment i'm running the first subscription twice which is ok because it's cheap, but it's not very elegant

valtteri10:08:13

You can subscribe to the previous step. One moment, I’ll try to make my self clear 🙂

valtteri10:08:38

Usually you can arrange your stuff so that you can compose your subs like this

(re-frame/reg-sub
 ::cats
 (fn [db _]
   (:cats db)))

(re-frame/reg-sub
 ::dogs
 (fn [db _]
   (:dogs db)))

(re-frame/reg-sub
 ::cat-ages
 :<- [::cats]
 (fn [cats _]
   (map :age cats)))

(re-frame/reg-sub
 ::dog-ages
 :<- [::dogs]
 (fn [dogs _]
   (map :age dogs)))

(re-frame/reg-sub
 ::total-age
 :<- [::cat-ages]
 :<- [::dog-ages]
 (fn [[cat-ages dog-ages] _]
   (reduce + (concat cat-ages dog-ages))))

valtteri10:08:07

And you can do artibrary computation at any of the steps and subscribe to that data in other subscriptions.

valtteri10:08:50

Ahhh now I read your message again and got your point. So you need earlier results further down the chain. Don’t be worried about the performance because intermediate results are cached.

valtteri10:08:33

If you need “raw cats” in the last step just subscribe to [::cats]

valtteri10:08:12

And now I read it again and I’m not sure if I get what’s the problem. 🙂 But as far as I understand I think you can just split the computation into different subs and subscribe to the intermediate results wherever you need them.

heyarne11:08:41

aah i see. you helped me a lot with your explanation, thanks!

👍 1
Simon Brooke14:08:11

Hi guys, I'm having a problem with an on-click handler, I wonder if anyone could help. Essentially I have a GDPR consent form, using signature-pad (https://github.com/szimek/signature_pad) to capture a signature. So when moving on from the form, I need to extract the signature from the signature pad and storing it in the database. I'm setting the on-click handler by setting a map including the key :on-click as the attributes of an element, and I'm logging to the console so I can see the function which sets the attributes is being called. But when I inspect the element, the on-click handler is not present, and when I click the element, nothing happens. Fuller explanation here: https://groups.google.com/forum/#!topic/clojure/D2iGl0jkaaM

Simon Brooke14:08:26

Any help exceedingly welcome!

henrik15:08:44

Did you wrap the on-click handler in #(…) as needed? It sounds like the function might be called in page load rather than on click.

dpsutton15:08:41

are you sure you want #(fn [] ...) and not just (fn [] ...)

henrik15:08:09

Drop the inner fn and try.

henrik15:08:56

Yeah, or (fn []… without #, as above.

Simon Brooke15:08:46

No apparent change. That might be figwheel failing to reload, hang on...

Simon Brooke15:08:14

Doing a clean and rebuild, to be sure, to be sure...

Simon Brooke15:08:47

H'mmm... stepping through in Javascript, it's because that's not actually being called...?!?

Simon Brooke15:08:59

Is there anything magic re-frame does with the value of :on-click keys?

conan15:08:27

never seen anything unusual, give it a function and it just calls it. It does pass in the on-click event, so maybe add that in as an arg to your handler function?

conan15:08:20

Hi, anyone had any luck with Microsoft Edge? I'm working with input elements, and need an :on-change handler, but if I include one then typing performance is prohibitively slow, even if the handler is a no-op (It's over 300ms for each button press when I'm emulating a Surface Pro 4, which is a fairly reasonable situation for our target audience). Re-frame-10x says the timing is all "misc", so I'm a little stumped as to what's going on. Any suggestions on how to debug further?

dpsutton15:08:10

@simon_brooke what do you mean keys? Your own ui helper function just changes :handler key for the on-click. Did you get rid of the doubly nested function?

Simon Brooke16:08:36

OK, I'm not clear what you mean by a double nested function; I've removed the #( and subsituted just (, but that makes no difference.

dpsutton16:08:46

(ui/big-link "I consent"
             ;; :target (str "#elector/" (:id elector) "/true/")
             :handler (fn
                        []
                        (ui/log-and-dispatch
                         [:set-consent-and-page {:elector-id (:id elector)
                                                 :page       :elector
                                                 :elector    (merge elector
                                                                    :signature
                                                                    (.toDataURL
                                                                     sig-pad
                                                                     "image/svg+xml"))}])))
note that there isn't a # in front of the fn.

dpsutton16:08:08

also your merge seems kinda weird. I don't understand what the keyword :signature is supposed to accomplish in the merge

dpsutton16:08:55

which might explain it. (merge {} :bob :apple) throws an error. is it possible you're throwing an error in the dispatch and not seeing it?

Simon Brooke16:08:52

Yes, that's what I now have. And you're right, that merge should be assoc...

Simon Brooke16:08:55

However, the interesting thing I've found is that if I change :on-click to :alt - and make no other changes, thus:

Simon Brooke16:08:10

(defn big-link [text & {:keys [target handler]}] (js/console.log (str "Big link with target '" target "'; handler '" handler "'")) [:div.big-link-container {:key (gensym "big-link")} [:a.big-link (merge {} (if target {:href target}{}) (if handler {:alt handler}{})) text]])

Simon Brooke16:08:57

I do get the function as alt text, but if I change it back to :on-click, I don't get an on-click handler...

dpsutton16:08:32

try onClick?

Simon Brooke16:08:19

Yes, confirmed. If I use an attribute name that's invalid, like :froboz, then no attribute is generated. If I use one that's valid but the value would just be text, I get the text of my handler. If I use :style, things go VERY weird; and if I use :on-click, like :froboz, I get nothing...

Simon Brooke16:08:25

OK, so this doesn't work either:

Simon Brooke16:08:40

(ui/big-link "I consent" :handler #(ui/log-and-dispatch [:set-consent-and-page {:elector-id (:id elector) :page :elector :elector (assoc elector :signature (.toDataURL sig-pad "image/svg+xml") )}]))

Simon Brooke16:08:09

(which is presumably the other solution to what you meant by 'double wrapped function').

Simon Brooke16:08:43

:onclick also results in nothing...

dpsutton16:08:59

one thing i would recommend is not use big-link. just use a simple structure and get it going. then you can diagnose if there's an issue with biglink or your handler

Simon Brooke16:08:23

Yes, that-s a good suggestion.

Simon Brooke16:08:41

OK, so what I currently have is this:

Simon Brooke16:08:43

(defn gdpr-render [] (let [elector @(subscribe [:elector])] [:div [:h1 "I, " (:name elector)] [:div.container {:id "main-container"} [:table [:tbody [:tr [:td [:p "Consent to have data about my voting intention stored by " [:b "Project Hope"] " for use in the current referendum campaign, after which it will be anonymised or deleted."] [:p [:i "If you do not consent, we will store your voting intention only against your electoral district, and not link it to you"]]]] [:tr [:td [:canvas {:id "signature-pad"}]]]]]] (ui/back-link "#dwelling") [:div.big-link-container {:key (gensym "big-link")} [:a.big-link {:on-click #(ui/log-and-dispatch [:set-consent-and-page {:elector-id (:id elector) :page :elector :elector (assoc elector :signature (.toDataURL sig-pad "image/svg+xml") )}])} "I consent"]] (ui/big-link "I DO NOT consent" :target (str "#elector/" (:id elector) "/false"))]))

Simon Brooke16:08:48

No on-click handler is generated, either using the key :on-click or the key :onclick.

Simon Brooke16:08:02

Tried :onClick as well, nothing.

Simon Brooke16:08:25

It also makes no difference if I change from an a tag to a span tag: still no on-click handler with any of :on-click, :onclick or :onClick

Simon Brooke16:08:19

Right, on another page I use :on-click, no 'on-click' attribute shows in the element which you inspect it, but nevertheless the value of the :on-click key is called when the element is clicked. So I think someone's suggestion upthread that my function is being called but is failing silently is probably right....

Simon Brooke16:08:41

Yes, that's correct. When I try [:a.big-link {:on-click #(js/console.log "Hello there") "Froboz"] I get Hello there in the console.

Simon Brooke16:08:53

Thanks everyone, I'm cooking with gas now.

Simon Brooke16:08:29

And the actual error was I was not handling my atom correctly. D'oh!

👍 1
madstap20:08:34

In the docs here https://github.com/Day8/re-frame/blob/master/docs/API.md#built-in-effect-handlers, there's an ambiguity (in my head at least) in the explanation of :dispatch-later. When I return the following from an fx handler:

{:dispatch-later [{:ms 200 :dispatch [:foo]}
                  {:ms 100 :dispatch [:bar]}]}
Does [:foo] get dispatched at t+200ms and [:bar] at t+300ms. Or does [:bar] get dispatched first?

madstap21:08:50

To answer my own question, [:bar] gets dispatched first, at t+100ms. The relevant part of the implementation: (set-timeout! #(router/dispatch dispatch) ms)

👍 2