Fork me on GitHub
#clojurescript
<
2019-02-04
>
Saikyun12:02:14

how do I get calva + play-cljs to work? I'm so confused about play-cljs wanting me to use boot, where calva doesn't even mention boot

devo15:02:09

boot is just an alternative build tool to leiningen. The template that oakes provides is catered to developing with boot + nightcode, but you can modify it to use lein or clj-cli if you know how to tweak it.

devo15:02:04

If you have lein installed you can just do lein new play-cljs my-dummy-project and then convert the build.boot to a project.clj for lein. After that you can follow the other steps for getting started with calva.

devo15:02:24

alternatively you can run the equivalent commands in that tutorial as boot commands.

devo15:02:45

i.e. boot repl.

Saikyun07:02:43

hi @U1RUG108P, thanks for your reply. sadly I don't know how to tweak it.

Saikyun07:02:35

okay, so it's possible to run calva + boot? seems easier. I'm guessing I just need to add the dependencies (nrepl/cider/figwheel) to boot then?

👍 5
Saikyun07:02:57

I'm very perplexed about how to get started with clojurescript, it's really hard

borkdude13:02:55

How do I call a multi-method from JS? I seem to be getting “is not a function” from the browser console

borkdude13:02:25

this works: dre.subnav.events.subnav_init_events.call(null, cljs.core.keyword("feeds")) (thanks to KLIPSE)

Yehonathan Sharvit15:02:49

Continuing on the topic of type inference, I found a simple interesting “use case” where the type inference is able to generate optimized code by not wrapping objects that are inferred as strings with an str call, as @mfikes explained it yesterday.

(defn booz [x]
  (str "Hello, " (inc x)))

(defn bar [^string x]
  (str "Hello, " x ))

(defn foo [x]
  (if (string? x)
    (str "Hello, " x )
    "No string"))
With bar and foo, x is not wrapped in a str call 🙂 You can play with it inside Klipse in order to see the transpiled code for different cases: http://app.klipse.tech/?cljs_in=(defn%20booz%20%5Bx%5D%0A%20%20%20%20(str%20“Hello%2C%20%22%20(inc%20x)))%0A%0A(defn%20bar%20%5B%5Estring%20x%5D%0A%20%20%20%20(str%20%22Hello%2C%20%22%20x%20))%0A%0A(defn%20foo%20%5Bx%5D%0A%20%20(if%20(string%3F%20x)%0A%20%20%20%20(str%20%22Hello%2C%20%22%20x%20)%0A%20%20%20%20%22No%20string”))

borkdude15:02:08

on the topic of type inference (but a little off topic for CLJS): https://twitter.com/borkdude/status/1091797983178473475

Ramzi16:02:41

Hello. I have a variable which is a large String with paragraph breaks in the form of \n. I would like to split this string by the \n, and produce a new textarea with that token as the content of the textarea. When I try to set the content of the textarea, bizarre generated Javascript makes it into the content. Similarly, when I try to alert the tokens of the split, I get the alert showing some generated Javascript. See pic:

Ramzi16:02:19

I am using reagent.

Ramzi16:02:28

Can someone help me produce a button that will produce a new textarea DOM element for each paragraph in the String, such that that generated Javascript doesn't become part of the content, as I've been getting? Thanks!

thheller16:02:00

@its.ramzi that looks like you are just passing the function as the textarea value instead of calling it and using the return value

thheller16:02:11

ie. content instead of (content)

Ramzi16:02:07

That was it! Thanks! I'm just picking cljs/reagent/clj back up after a few months off, so I'm pretty rusty. (And I was never that great!)

Ramzi16:02:44

What am I doing wrong here? (for [s (clojure.string/split-lines content)] (js/alert s))

dpsutton16:02:33

for returns a lazy collection. Nothing is realizing your collection so no side affects are happening

borkdude16:02:44

wrap it in a doall

dpsutton16:02:08

try (doseq [s (... as that makes a bit more sense with respect to what you are trying to achieve

Ramzi17:02:27

Interesting. I wonder why Chrome didn't give me the option to prevent further pop-ups...

Ramzi17:02:38

So I've got what I want working with js popups. How can I do this with new textareas now? Doing simply [:textarea s] where I had (js/alert s) before isn't doing it. I am thinking I need some kind of addDomElement or addChildNode kind of function. I looked into this earlier, and got one Stack Overflow answer, but I couldn't comprehend the code or get it to work. The code clearly involved specifying some DOM element to add a child to, along with what that child's ID should be. Please tell me the simplest way to do this, what I assume to be a very common and easy, Clojurescript task. Thanks!

borkdude17:02:42

are you doing reagent/react or straight dom programming?

Ramzi17:02:52

Reagent/React, I believe

Ramzi17:02:05

I just started the project with lein new reagent-frontend mindmeld

Ramzi17:02:40

Not that I'm opposed to vanilla js, or "straight dom programming" if it's easy enough to write in cljs.

Ramzi17:02:02

Oh. I see what you're saying! Look up how to do the vanilla js stuff, then look up how to represent the vanilla js stuff in clojurescript. Gotcha! Thanks!

Ramzi17:02:11

Okay, one error I got said you can't call .append on null, which makes sense to me because right now my line 11 doseq is running before the "main-content-area" DOM element is created on line 23.

Ramzi17:02:55

But I get the same error even when I move the doseq below the home-page defn

borkdude17:02:55

@its.ramzi I recommend doing a Reagent tutorial first

borkdude17:02:35

you can’t just add vectors as dom-elements

Ramzi17:02:05

I thought I was adding [:textarea s] as a DOM element. Is that a vector? I didn't think so...

Ramzi17:02:18

I thought the only vector I was working with was from the string/split, but that must not be right because that's passing to a doseq, so it must be a sequence, which is a different word than vector.

ccann17:02:24

can anyone clue me in — how do I await a javascript promise from a library using clojurescript?

thheller17:02:23

@ccann CLJS does not support await so you do (.then the-promise (fn [val] ...))

ccann17:02:31

okay cool

Ramzi17:02:52

So... How to add a new DOM element at the click of a button? 😞

lilactown17:02:48

hey @its.ramzi. it looks like you have a lot of fundamental question about ClojureScript and Reagent, that might be hard to answer all of them over chat

Ramzi17:02:10

I've tried translating the vanilla Javascript to CLJS using an online converter. No matter what I try, it is basically telling me I cannot call .append on null. So I am thinking that I do not understand the timing of when the DOM elements are created compared to when the Javascript is run.

lilactown17:02:44

it looks like you got linked to https://www.learnreagent.com/, which has a free 12 videos on trying to do the kinds of things you're talking about

Ramzi18:02:04

You promise if I watch those 12 videos these answers will fall in line?

lilactown18:02:27

I don't promise that 😄 but you might have a better idea of how to approach these

Ramzi18:02:39

Okay. Thanks.

lilactown18:02:04

to answer your latest question, there's a couple things wrong with your code you pasted above

lilactown18:02:15

doseq executes immediately, so it sounds like it's firing before you have rendered your "main-content-area" div to the web page

lilactown18:02:36

it looks like you're using Reagent, which renders asynchronously. so even if you put it after the call to reagent.core/render, it's still not guaranteed to be put on the page

Ramzi18:02:16

Why am I wrong to think that a function to add a new DOM element to a page should be Clojurescript 101 easy-peasy?

lilactown18:02:46

well, it is relatively simple to add a new DOM element to a page if you just use JS interop

lilactown18:02:27

the problem you're encountering, is that you're using Reagent, which has opinions 😅 about how to do things. one of those opinions is that you shouldn't be mutating the DOM like you are

jimberlage18:02:55

The first issue lilactown mentioned, about the textareas being added before the #main-content-area is on the page, would be an issue even if you were just doing JS

☝️ 5
lilactown18:02:06

Reagent == React + some bits. You would be struggling the same if you were just using React

Ramzi18:02:15

Right. I jumped right to Reagent and I never went through any React tutorials. But, in my previous experience, I figured out simple helper functions, like how to manipulate the DOM in a way that I guess is against Reagent's opinions... And I was able to keep building off that. Whereas here I'm struggling to even make those initial helper functions which are required for further building.

lilactown18:02:21

you shouldn't need to go through any React tutorials. but it's a fundamentally different way of programming than raw JS

Ramzi18:02:28

If Reagent's opinion is that I should not be mutating the DOM in this way... Then how do I dynamically add and remove things from a page in Reagent? I thought all dynamically adding and removing things on the page had to go through DOM. 😞

lilactown18:02:28

so there's some impedance mismatch

lilactown18:02:12

there are lots of tutorials that would help with that 🙂 e.g. the learnreagent site

jimberlage18:02:28

There’s a concept called a reagent atom, which triggers changes to the DOM

lilactown18:02:43

the TL;DR is that you use reagent's state management to conditionally render certain things inside of your reagent component

jimberlage18:02:07

In both reagent and react, you change some state, and then react tries to figure out what needs to change on the page.

Ramzi18:02:40

So what I'm hearing is: - I should stop with vanilla JS DOM manipulation - I should study the learnreagent tutorial

Ramzi18:02:12

Okay. Thanks for the direction.

lilactown18:02:28

the reagent website also has some examples to get you started: https://reagent-project.github.io/

thheller18:02:32

if you want to learn reagent. it is totally fine to do straight dom manipulation but it is rather uncommon in the CLJS world

Ramzi18:02:49

I've looked into form-1, form-2, form-3 stuff before. Am I wrong to think: Everything should just be form-3. And that all form-3's basically look a certain way. And form-3's will have the React keywords necessary for rerendering a component after a change? Can I thus skip the tutorials and just figure out how to make the glorious form-3 component with the magical keywords for rerendering?

lilactown18:02:56

I would say 80% of your components will be form-1. 18% will be form-2

lilactown18:02:58

form-3 is really for when you need to do heavy interop with either React or the DOM

Ramzi18:02:39

Okay. I'll go through the tutorials. Thanks.

jimberlage18:02:22

So you can compare the two, here’s your original example “reactified”:

jimberlage18:02:28

(ns 
  (:require [clojure.string :as cs]
            [reagent.core :as reagent]))

(def app-db (reagent/atom {:lines []}))

(defn content []
  "lorem\nipsum") 

(defn home-page []
  (let [lines (reagent/cursor app-db [:lines])]
    (fn []
      [:div
       "This is what a node looks like"
       [:br]
       [:br]
       [:div {:id "main-content-area"}
        (map (fn [line]
               [:textarea {:key line} line])
             @lines)]])))

(reagent/render [home-page] (aget (.getElementsByTagName js/document "body") 0))

(swap! app-db assoc :lines (cs/split (content) "\n"))

bringe20:02:11

Hello. I'm a beginner at clojurescript but have been using clojure for some time now. I'm wondering, when using clojurescript, is it normal/ideal to use clojure libraries in a clojurescript project? Or should I lean toward the javascript ecosystem when using clojurescript?

kwladyka12:02:32

https://github.com/kwladyka/form-validator-cljs/tree/doc here you have example how to use JS deps in CLJS.

kwladyka12:02:05

https://github.com/kwladyka/form-validator-cljs/blob/doc/src/js/index.js This is the hardest part. Everything else is “normal” I would say.

Charles20:02:08

I tend to almost exclusively use clojurescript, there's an odd powerhouse library that I'll import

Charles20:02:44

I also find in the past it's almost always been easier / more succinct to re-write my own components in clojurescript than to try to adapt an off-the-shelf javascript one

cjohansen20:02:15

javascript libraries also tend to have a terrible track record when it comes to backwards compat etc, so beware the cost of using them

cjohansen20:02:29

much less of a problem with clj deps in my experience

bringe20:02:05

I see. Thanks for the info.

cjohansen20:02:52

1. Are you sure you need to add more dependencies? 2. Really sure? 3. Is there a clj one? 4. Would it be a lot of work to write one? 5. Is there a good JS one?

cjohansen20:02:02

that's roughly my decision tree 🙂

bringe20:02:53

Ahh thanks this helps a lot

bringe20:02:04

So I'm working on displaying a directed acyclic graph based on a vector of custom structures that basically defines a data pipeline. The data isn't in a DAG structure, but it does represent one based on the input/output pointers of each map. So my thoughts are to first put it into an actual DAG data structure (libraries exist for this) and then display it via svg and maybe canvas (libraries also exist for this).

bringe20:02:20

I started to use loom, and that was when I realized I can't just pull that in and use it.

Ramzi20:02:53

And those existing DAG libraries are Java, not Javascript, right?

Ramzi20:02:45

If Java has the DAG library, and the image drawing library, why not just use Clojure rather than Clojurescript? Why are you keener to output the image of your graph as a SVG rather than as a PNG in your home directory? Are you running this for a personal project, or are you trying to make a user friendly page for others to use? Unless I'm way off base here... Doing a lein new reagent yourprojectname will give you a project with the Java/Javascript hookup there. So use the heavy DAG and drawing libraries server side, and just pass the final image to the browser.

Ramzi20:02:21

Does anyone know the keyboard command to pull up nRepl in Atom in Windows? I've been looking all over for this with no luck.

jimberlage20:02:51

@brandon.ringe for an easy way to start, there’s an existing clojurescript package wrapping the cytoscape graph library: https://github.com/cljsjs/packages/tree/master/cytoscape

Ramzi20:02:18

Apparently settings says it's Control+Alt+E. And then something flickers and disappears. 😞

Karol Wójcik20:02:27

what do you use to make http requests?

bringe20:02:33

@jimberlage I actually just noticed this right before I read your message 😃. Looks awesome.

bringe20:02:34

@its.ramzi Good points. This is for others on an internal team to use. I wanted something that could be easily scalable and interactive, and SVG was what I'm most familiar with in that realm. But maybe I should try to look at more java/clojure server-side processing and then sending the data to the client like you said. I'll look into cytoscape too.

Ramzi21:02:19

I just finished lecture 4/12. These are wonderful. He's so clear. I've learned so many things that were scary looking. Like the @ So simple now. But my user experience with Atom has not been so nice. I am on Windows, and he's not. The keybinds aren't the same. I've tried installing special packages and setting up the keybinds. And I can't get the repl to play nice, or for the server to auto reload changes... Like how I know how to do in Reagent. But coding wise, he has been so clear. I'm hoping I don't have to get my IDE working like his in order to learn the code, to then go back to using lein figwheel Reagent, which I'm more familiar with.

ag21:02:43

I need to assoc a value. but I want to do it in Dev Tools’s console using javascript. Can someone tell me the correct syntax? cljs.core.assoc(re_frame.db.app_db,,,, help me please to finish this. I need to assoc a key to reframe’s db

ag21:02:26

oh… pshtt… /I’m stupid/ it’s gotta be an swap! or something

jimberlage21:02:17

(swap! re-frame.db/app-db assoc :key :value)

ag21:02:31

yeah… now translate this to js

jimberlage21:02:36

Oh using javascript, don’t mind me

ag21:02:21

Oh… I think this worked: cljs.core.swap_BANG_(re_frame.db.app_db, cljs.core.assoc, cljs.core.keyword("pi"), 31415926)

ag21:02:45

holy cow, javascript is darn ugly

jimberlage21:02:18

cljs.core.swap_BANG_(re_frame.db.app_db, cljs.core.assoc, "foo", "bar");

jimberlage21:02:24

Oh, you got it

jimberlage21:02:29

That seems to work for me

jimberlage21:02:41

cljs.core.get(cljs.core.deref(re_frame.db.app_db), "foo"); // "bar"

ag21:02:02

well now I actually need to use assoc-in. Does anyone know a service that compiles cljs snippets to javascript interactively? excluding all the “garbage”

ag21:02:49

klipse does that, doesn’t it?

darwin23:02:43

@ag it is called “a working CLJS REPL”, it is worth it IMO 🙂

darwin23:02:05

if you really want to stay in DevTools console, you could try Dirac: https://github.com/binaryage/dirac (I’m the maintainer)

ag23:02:58

Yeah I’ve tried Dirac once… long time ago. It was painful to setup. Maybe I should try again. The js thing I needed though for a bookmarklet

darwin23:02:39

another idea: you can get working CLJS REPL via clj -m cljs.main (assuming your ~/.clojure/deps.edn contains clojurescript dep)

ag23:02:01

No, I mean Klipse thing worked for creating a simple bookmarklet. I usually don’t have to do that. It’s really indicative of something (probably awesomeness). For almost 3 years of using Clojurescript I have never, ever needed to bother about transpiled output js.

ag23:02:06

until today

darwin23:02:39

so you have solved it with Klipse, nice!

darwin23:02:18

just to add when I have a CLJS REPL and want to see the js code a form would generate I do something like (.toString (fn [] (+ 1 2)))

ag23:02:46

oh… yeah… that’s right

darwin23:02:18

of course the tricky part is that sometimes code generated depends on your CLJS compiler environment, so it works for simpler “global” cases

jsa-aerial23:02:07

It is a bit unclear - is js-arguments what you use for the Javascript arguments inside a function?

👍 5
jsa-aerial23:02:26

OK, does that mean this would be legitimate use: (f.apply (js-arguments)?

darwin23:02:37

(.apply f nil (js-arguments)) could work, or maybe you need to convert js-arguments to js array first

darwin23:02:04

not sure if js apply can accept Array-like argument like arguments

darwin23:02:41

ok, did a bit of googling, should not be needed according to: https://stackoverflow.com/a/20375156/84283

jsa-aerial23:02:50

Hmmm, I'm working from a snippet of code to fix an aspect of react (from the react devs actually). In it it has this: originalRemoveChild.apply(this, arguments)

darwin23:02:51

you might need to use this-as to get the this value to pass it into .apply

jsa-aerial23:02:01

yes, I have that

darwin23:02:33

so something like this? (this-as my-this (.apply originalRemoveChild my-this (js-arguments)))

jsa-aerial23:02:40

so, my version is : (orig-rm-child.apply this (js-arguments))

jsa-aerial23:02:26

ah - I thought I could just use the same JS dotted notation. In the repl it shows x.apply (for valid x) shows as the function apply

darwin23:02:06

I’m not sure, yours might work

jsa-aerial23:02:19

Thanks for the help!

🍻 5
jsa-aerial23:02:03

FYI - your version is correct - mine is wrong. You can use dotted notation for properties that are not functions

👍 5
Ramzi23:02:50

So, I finished the learnreagent free course. I felt like it started to go fast super fast. I guess I'll be buying the pro course. It seemed like indenting made a difference here, and that wasn't the case in what I was used to. Maybe I'm wrong. It just seemed like everything worked out too perfectly for him. Everything rendering so neatly and nicely. With me, I couldn't add a horizontal row without it intersecting a previous DOM element.

lilactown23:02:09

@its.ramzi the editor setup the author is using probably includes Parinfer, which helps you align your braces and parentheses according to your whitespacing

lilactown23:02:25

it's not required for editing Clojure code, but some people like it

lilactown23:02:01

did you try following along with his examples? I believe there's a repository you can download and fiddle with