Fork me on GitHub
#clojurescript
<
2020-11-22
>
tskardal09:11:44

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?

p-himik09:11:57

Just create a closure.

(defn init-comp [stuff]
  (let [state (atom stuff)]
    (fn [other-stuff]
      (println "New stuff:" (reset! state other-stuff)))))

p-himik09:11:14

It's absolutely the same as you'd do in JS.

tskardal09:11:08

Got it! Thanks 🙂

tskardal09:11:57

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?

tskardal14:11:12

When building a "production build" it works fine. Why is that?

p-himik14:11:16

Just place the JS code right after the <script> that loads the CLJS bundle.

tskardal18:11:20

That’s what I did :man-shrugging:

tskardal18:11:45


<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>

p-himik18:11:14

Are you exporting the counter.core/run function?

p-himik18:11:38

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?

tskardal18:11:40

if I compile it like this it works:

clj -m cljs.main --optimizations advanced -c counters.core

tskardal18:11:46

if I compile it like this, it doesn’t:

clj --main cljs.main --compile counters.core --repl

p-himik18:11:21

What if you just drop the --repl part and leave the rest of the arguments?

p-himik18:11:03

Hold on, there's no counters namespace in that code.

tskardal18:11:04

ah 😅 you are right, but that’s kind of expected 😛 I’ve renamed the package when pasting code here

tskardal18:11:23

in the repo it is clickbait.core

p-himik19:11:45

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.

tskardal19:11:26

if you get three counters, yes

p-himik19:11:32

Ah, hold on.

p-himik19:11:08

Ahh, right, I see. The development bundle uses document.write that writes <script> tags after the relevant line with clickbait.core.run.

p-himik19:11:06

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.

tskardal20:11:54

Ah, I see. Thanks for clarifying 🙂

Milan Munzar19:11:41

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.