This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-07-08
Channels
- # aleph (10)
- # announcements (2)
- # babashka (1)
- # beginners (22)
- # biff (5)
- # calva (1)
- # clj-kondo (46)
- # clj-on-windows (7)
- # clojure (88)
- # clojure-denver (12)
- # clojure-europe (41)
- # clojure-losangeles (1)
- # clojure-norway (6)
- # clojurescript (5)
- # conjure (4)
- # fulcro (13)
- # humbleui (1)
- # hyperfiddle (70)
- # jobs (5)
- # juxt (1)
- # meander (12)
- # off-topic (42)
- # practicalli (6)
- # releases (2)
- # shadow-cljs (12)
- # tools-deps (1)
How can I invoke some callback after an element is actually loaded?
I'm trying to use mermaid to render some content and it requires calling (.run js/mermaid (clj->js {:querySelector ".mermaid"}))
after the mermaid class has content (which is fetched from the server).
I wonder how I can know when the content was actually generated since there are no elements that support onload in dom/*
.
I tried stuff like:
(when (not (s/blank? mmd))
(try
(dom/div (dom/props {:class "mermaid"})
(println "rendering" mmd)
(dom/text mmd))
(finally (.run js/mermaid (clj->js {:querySelector ".mermaid"})))))
Or:
(when (not (s/blank? mmd))
(dom/div (dom/props {:class "mermaid"})
(println "rendering" mmd)
(dom/text mmd)
(.run js/mermaid (clj->js {:querySelector ".mermaid"}))))
But it seems run
(which returns a promise) still happens before the content is actually loaded.When you say "it [content] is actually loaded" what exactly are you referring to as "content"
the class should exist and should contain the mmd. I should have mentioned mmd is a reference (?) it is defined as a watch (?) because it is communicated from the server. To give the overall perspective I have mmd files (mermaid files) on the server and I want to display them on the client. The client cannot download them directly via links, so I'm using a reference (atom + watch) by looking at examples. This is the definiton of mmd:
(e/server
(let [!mmd (atom "")
mmd (e/watch !mmd)]
(mmd is just a string)
(let [x (e/server "foo")] (case x (js/mermaid.run ...)))
this is an idiom we currently use that exploits the fact that the conditional node cannot evaluate it's body until after the remove value is available, i.e. if x
is pending the control flow is blocked until we can test it
(here we are using the default branch)
I'll try and see what you mean
oh I think I get it actually, sec
It would be better if you could write (js/mermaid.run (e/server ...)), where the Electric evaluation rules will delay the .run until the parameter is available
isn't my when
(in the original message) doing exactly that though?
hmm yes
the mermaid/run method receives selector (among other things) to render the matching elements. It does not receive mermaid strings.
Can you post a minimal (complete) example that runs
let me edit it to be minimal, it can take a while
oh, i think what's happening is that mmd
starts ""
and then later receives a value? in this case js/mermaid.run
does not have a dependency on mmd
and therefore Electric will not re-evaluate it if it has already ran
It is idiomatic to wrap it like (defn mermaid! [_mmd] ...) to force the dependency explicitly
(e/defn Observer []
(e/server
(let [!mmd (atom "flowchart LR\n\nA-->B")
mmd (e/watch !mmd)]
(e/client
(.initialize js/mermaid {:startOnLoad true})
(when (not (s/blank? mmd))
(try
(dom/div
;; doesn't work
(dom/div (dom/props {:class "mermaid"})
(println "rendering" mmd)
(dom/text mmd))
;;works
(dom/div (dom/props {:class "mermaid"})
(println "rendering" mmd)
(dom/text "flowchart LR\n\nA-->B")))
(finally (.run js/mermaid (clj->js {:querySelector ".mermaid"})))))))))
the try-finally is just an attempt it could not make sense at all 🙂
yeah i dont think the try/finally is helping you here
just wanted to write the run somewhere
I think creating a dependency worked, checking on the "real" code now
This worked:
(defn mermaid! [_mmd]
(.run js/mermaid (clj->js {:querySelector ".mermaid"})))
And then:
(when (not (s/blank? mmd))
(try
(dom/div (dom/props {:class "mermaid"})
(println "rendering" mmd)
(dom/text mmd))
(finally (mermaid! mmd)))))))))
why try/finally
where would you invoke mermaid!
?
invoke it like println
would it work coincidentally because it's a promise?
i dont understand
doesn't println
happens before dom/text
is generated?
(dom/div
(do
(dom/props {:class "mermaid"})
(dom/text mmd)
(js/mermaid.run #js {:querySelector ".mermaid"})))
i have added the explicit do
to clarify what is happening
it throws some warning like that
let me re-check
Unserializable reference transfer: #object[Promise] [object Promise]
it's not really generating anything dom-able
so I don't like it
i dont understand what you don't like?
what don't you like and why
It gives me this warning on the repl:
Unserializable reference transfer: #object[Promise] [object Promise]
the warning can be ignored, i will explain that in a moment, it is harmless, i will also explain how to fix the warning
ok, but I don't want to take too much of your time
i want to know "what don't you like and why" Its just the warning that concerned you?
I can mess with it some more and learnt he conventions later
I think the warning is based on it not being embeddable in the dom (returns promise)
but that's just intuition
that's not it
the warning is because the promise is returning up the "stack" into an e/server block
I have no idea what that means
if there is a link feel free to direct me there and let me learn the hard way 🙂
but I'm very focused on making things work so I can show it at work tomorrow
(e/server (e/client (js/Object.)))
will warn because the reference cannot be serialized with transit to move over network to the server
only values can move over network, promise is a ref type and cannot be serializable
(e/server
(let [x (e/client
(dom/div
(dom/props {:class "mermaid"})
(dom/text mmd)
(js/mermaid.run #js {:querySelector ".mermaid"})))]
x))
x is the promise and it will fail to transferoh now I understand what you said about the stack
I think
the dom elements wrap their children forms in an implicit do (for effect) and return the final element
I have another meeting now Dustin, but I will continue my exploration later
The communication (through datascript) is just incredible! I can't imagine building an api this specific so easily in something like re-frame and rest. Can't wait to test this as an actual service to see how performant it actually is. I built a small ui to see the data flow through the services in the company that employs me. It's not done but I'm getting the hang of it.
For future reference to those who search in slack: Seems like mermaid dynamically updates the dom in a way electric doesn't like. It appends an svg to the dom (under the mermaid class) and then (for me) it stopped responding (changing mmd doesn't change the dom anymore). I ended up doing it manually like this:
(e/defn Mermaid []
(e/client
(try
(dom/div (dom/props {:class "mmd"})
(dom/div (dom/props {:id "mermaid"})
(dom/text svg)
(.then
(.render js/mermaid "dummy" mmd)
(fn [svg] (let [e (.getElementById js/document "mermaid")]
(println "element" e)
(println "svg" (.-svg svg))
(set! (.-innerHTML e) (.-svg svg)))))
nil))
(finally
(mermaid! mmd)))))
There are probably better solutions but I don't want to figure it out right now.Is there a way to use raw html. Say there is an avg I want to use as pure code instead of pulled in as an image.
I can also convert all to the tags to ‘(dom/…)’ I was just wondering if there was a dirtier faster way
or use a svg file, surely there is a way