This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-07-02
Channels
- # beginners (130)
- # calva (3)
- # cider (13)
- # circleci (1)
- # cljsrn (19)
- # clojure (106)
- # clojure-europe (10)
- # clojure-losangeles (1)
- # clojure-nl (9)
- # clojure-uk (33)
- # clojurescript (16)
- # code-reviews (24)
- # conjure (11)
- # cursive (41)
- # data-science (9)
- # datomic (63)
- # fulcro (19)
- # graphql (12)
- # helix (4)
- # kaocha (2)
- # leiningen (3)
- # malli (8)
- # meander (1)
- # off-topic (17)
- # re-frame (16)
- # reitit (12)
- # sci (32)
- # shadow-cljs (73)
- # spacemacs (31)
- # sql (38)
- # tools-deps (26)
- # xtdb (28)
Hello, got a quick question. I've been learning re-frame lately and came across a scenario in my app where I want to call .focus
on an html element that only appears in the dom after an event (registered with reg-event-fx) is handled.
I made the call to focus the element an event with reg-event-fx
and used a dispatch
effect in the causal event with the ^:flush-dom
metadata on the event vector to make sure the element is rendered before .focus is called. If it weren't for needing that flush though, I would just use reg-fx
. Is there no way to flush the dom before an effect registered with reg-fx
is run?
Here's the code. If it weren't for needing to make sure the dom was rendered before ::focus-html-element
, I would just use reg-fx
to register it, because I'm not changing the db or returning any effects. Just wondering if this is idiomatic I guess.
To avoid complications, you could perhaps use the auto-focus
attribute?
(defn view
[]
[:input {:type "text" :id "fname" :auto-focus true])
This only works once, when the widget is first rendered which may not give enough control, but it sure is simpler.Also I think it doesn't work in Safari which is sadly IE of the current time 😞
If that doesn't give you enough control, you could create an effect which hooks into Reagent's after-render
https://github.com/reagent-project/reagent/blob/master/src/reagent/core.cljs#L340-L346
(reg-fx
:focus-html-element
(fn [element-id]
(reagent/after-render #(some-> js/document (.getElementById element-id) .focus)))
Note the use of some->
to avoid any weird corner cases
@brandon.ringe I tend to leave re-frame out of that type of very view specific logic / close to DOM and use Reagent Form-3 components for that. Something like this should do the trick:
(defn focus-input []
(let [ref (atom nil)]
(r/create-class
{:component-did-mount
(fn [_]
(.focus @ref))
:reagent-render
(fn [_]
[:input {:ref #(reset! ref %)}])})))
Interesting, this looks possibly more efficient than the .getElementById
method since it avoids the lookup. Maybe not significant, but still.
@brandon.ringe Here’s one more that should work - if you want to use it and have trouble let me know and I’ll double check (writing code on my phone is not always a good idea)
[:input {:ref #(when % (.focus %))}]