How would you go about making a reusable component/widget (with state!) in cljs that can be instantiated multiple times from js? How can I make each instance have its own atom?
Just create a closure.
(defn init-comp [stuff]
(let [state (atom stuff)]
(fn [other-stuff]
(println "New stuff:" (reset! state other-stuff)))))
It's absolutely the same as you'd do in JS.
Got it! Thanks 🙂
Another beginner question: when calling my cljs code (in ns counter.core) from js, I get the error ReferenceError: counter is not defined
. I tried placing the code in an event handler for DOMContentLoaded
, but with the same result. If I make the same call from the developer console it works. When is the cljs code ready to use?
Just place the JS code right after the <script>
that loads the CLJS bundle.
That’s what I did :man-shrugging:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="c1"></div>
<div id="c2"></div>
<div id="c3"></div>
<script src="out/main.js" type="text/javascript"></script>
<script type="text/javascript">
function ready(callbackFunction){
if(document.readyState != 'loading')
callbackFunction(event)
else
document.addEventListener("DOMContentLoaded", callbackFunction)
}
ready(event => {
console.log('DOM is ready.')
// nope
//counter.core.run(document.getElementById("c3"));
})
// also nope
counter.core.run(document.getElementById("c3"));
</script>
</body>
</html>
Are you exporting the counter.core/run
function?
Yes
No idea - the exact same patter has worked for me multiple times, unless I'm missing something. Can you create a minimal reproducible example on GitHub?
if I compile it like this it works:
clj -m cljs.main --optimizations advanced -c counters.core
if I compile it like this, it doesn’t:
clj --main cljs.main --compile counters.core --repl
What if you just drop the --repl
part and leave the rest of the arguments?
nope
I pushed it to a github repo https://github.com/tskardal/cljs-counters
Hold on, there's no counters
namespace in that code.
ah 😅 you are right, but that’s kind of expected 😛 I’ve renamed the package when pasting code here
in the repo it is clickbait.core
In a clean copy of your repo, my steps were:
- Run clj --main cljs.main --compile clickbait.core
- Edit index.html
so it only has the clickbait.core.run(document.getElementById("c3"));
line in the last <script>
tag
Works perfectly, as far as I can tell.
if you get three counters, yes
Ah, hold on.
Ahh, right, I see. The development bundle uses document.write
that writes <script>
tags after the relevant line with clickbait.core.run
.
OK, I think now I have the full picture. You cannot really add stuff to index.html
. You have to add it to one of the CLJS files.
Alternatively, use a more advanced build tool than the vanilla cljs.main
. Shadow-cljs has an :init-fn
build parameter for that.
Ah, I see. Thanks for clarifying 🙂
When building a "production build" it works fine. Why is that?
Hey, I have done some https://github.com/mimunzar/CommandLine/tree/master/scripts for cljs compiler and test outputs which you might find useful when developing on Node. There is also a script which generates Cljs project and makefile.