Fork me on GitHub
#clojurescript
<
2020-11-27
>
Nazral08:11:08

Is there something that behaves like agent in clojurescript ?

Nazral08:11:44

I'd like to port my clojure library to cljs but it uses agent because it needs their asynchronicity

Nazral08:11:11

Or I guess I can use reader conditionals to use an atom when using cljs and an agent when using clojure

oliver08:11:29

According to the https://clojurescript.org/about/differences#_concurrent_programming “Agents are currently not implemented”.

Nazral08:11:28

I know, hence my question 😛

oliver08:11:46

fair engough 😅

thheller08:11:41

javascript is single-threaded so agent would just act like atoms

Nazral08:11:40

Makes sense, thank you

leonoel08:11:38

not exactly, e.g for nested updates the ordering of operations in not the same

Yuner Bekir09:11:29

Hello. I am trying to open a file dialog box. I tried the following code without any results. (.. js/document (getElementById "file-upload") click) When I tried running `document.getElementById("file-upload").click()` the dialog opened. Could you suggest a fix?

thheller09:11:13

there are limits in what the browser lets you do. for security reasons certain things are only allowed when actually triggered by a user event and so on. you can't just randomly open a dialog box like that, browser will block or just ignore the request. trying to do that in the browser console may bypass those restrictions.

Yuner Bekir09:11:03

The interesting thing is that the on-click event handler is called, but the dialog is not displayed. My use case is the following: I am in tab A, when I click a button in A I have to navigate to B and click a button which opens the file dialog. Maybe a way to do it would be to navigate to B but open the dialog before navigation from A

thheller09:11:37

yeah browser restrictions are weird in some cases. I can't remember the exact rules either but my guess would be that is the cause of your issue.

Yuner Bekir09:11:07

thanks for your help

Sophie09:11:22

Hey Guys, I'm kind of stuck with the same problem for weeks now. I'm pretty sure the solution is quite simple but I didn't get it on my own. So here's the problem: I have a text input field with a value. The value is within a nested atom so it's mutable, in theory 😉...   With a simple atom it's working, but not with a nested one.  At first I can't change the value in the input field and second if I choose for an input field without value I can change it but the output doesn't change. That's the code:

(defn inputPage [title rNames rSizes rCost url]
    (let [room-property (r/atom {:title title
                                 :name rNames
                                 :Size rSizes
                                 :Costs rCost
                                 :img-scr url})]
      (if-not (blank? rNames)
        [:div {:class "inputLine"}
         [:img {:src url :class "roomImg"}]
         [:LineContainer
          [:TextLine [:p {:class "headLine"} [:b rNames " " ]  [:comment "(" (zeroDec (* rCost dd-costKey))" €/qm)"]]
           [:p {:class "roomLine"}   (:Size @room-property) " qm, " [:class {:class "result"} [:u "Summe: " (zeroDec (* rCost dd-costKey rSizes))" €"]]]]
          ]

         [:span
          [:b rNames " " ]
          [:input {:type "text"
                   :name :Size
                   :value (:Size @room-property)
                   :on-change #(reset! [room-property :Size] (-> % .-target .-value))}]
          [:p {:id "eOutputCell" } (:Size @room-property) ]]]

     

        ))

  )
I solved it finally. The hints from thheller and lassemaata where very helpful. Thank you Guys. The solution was a fn [] around the component. So this is it:
(defn atom-input [value]
  [:input {:type "text"
           :value (:Size @value)
           :on-change #(swap! value assoc :Size (.. % -target -value))}]
  )




(defn inputPage [title rNames rSizes rCost url]
    (let [room-property (r/atom {:title title
                                 :name rNames
                                 :Size rSizes
                                 :Costs rCost
                                 :img-scr url})]
      (if-not (blank? rNames)
        (fn []
          [:div {:class "inputLine"}
           [:img {:src url :class "roomImg"}]
           [:LineContainer
            [:TextLine [:p {:class "headLine"} [:b rNames " " ]  [:comment "(" (zeroDec (* rCost dd-costKey))" /qm)"]]
             [:p {:class "roomLine"}   (:Size @room-property) " qm, " [:class {:class "result"} [:u "Summe: " (zeroDec (* rCost dd-costKey rSizes))" "]]]]
            ]

           [:span
            [:b rNames ": " ]
            [atom-input room-property]
            [:p {:id "eOutputCell" } (:Size @room-property) ]]])


        [:div {:class "inputLine"
               :onClick #(testPage rSizes) }
         [:plus]]

        ))

  )

3
thheller09:11:48

#(reset! [room-property :Size] (-> % .-target .-value)) is not valid. you are calling reset! on the vector. you want to use swap! and assoc

Sophie09:11:30

Thanks I will try it. But what is the reason I can't change the input field? There must be anything totally wrong. 😞

thheller09:11:40

it keeps the current value because you :on-change fails, see https://reactjs.org/docs/forms.html#controlled-components

Sophie09:11:44

Ok nice thanks for the explanation and the link. I'm not aware that there are dependencies between.

lassemaatta09:11:08

also, shouldn't that component return a function? otherwise the atom is re-initialized every time the arguments change? (disclaimer: I haven't done cljs in ages)

👍 3
thheller09:11:30

that too probably

Sophie09:11:05

😂I have absolutely no idea what you guys are talking about. I'm an absolute beginner but I will work through the links and hopefully I will understand your remarks after that. Thank you so much

lassemaatta09:11:14

it might also be a good idea to check out the reagent documentation, e.g. https://github.com/reagent-project/reagent/blob/master/doc/CreatingReagentComponents.md

borkdude14:11:43

Where in the CLJS tests can I find the unit tests for JS interop like (.- ...), (.. ...) and (js/foo.bar ..) etc?

Braden Shepherdson16:11:12

oh boy do I feel dumb. I just learned the hard way that (prn ..) in a macro emits the printed text into the compiled file, at least under Figwheel main dev builds.

Braden Shepherdson16:11:43

it happened that the output in my case kinda resembled JS code, and I was getting syntax errors in the browser that made no sense at first.

dpsutton16:11:04

i think *out* is bound to the output file during compilation?

Carlo21:11:36

I'm executing this code from a cljs file, after installing cystoscape via npm (I'm using shadow-cljs

(ns minimal.core
    (:require
      ["cytoscape" :as cytoscape]))

(def graph
  (cytoscape
   (clj->js {:container (.getElementById js/document "graph")
             :elements [{:group "nodes" :data {:id 1 :immediate "a"}}
                        {:group "nodes" :data {:id 2 :immediate "b"}}
                        {:group "edges" :data {:id 12 :source 1 :target 2 :immediate "meh"}}]
             :style [{:selector "node"
                      :style {:label "data(immediate)"}}]})))
This works, and displays everything as wanted, but then I do:
(.add graph (clj->js {:group "nodes" :data {:id 3 :immediate "c"}}))
and it works, but in the browser console I also get:
Collection [Element(1), _private: {…}]0: Element [Element(1), _private: {…}]length: 1_private: {eles: Collection(1), cy: Core, rebuildMap: ƒ}__proto__: Array RangeError: Maximum call stack size exceeded
    at Object.eval [as cljs$core$ILookup$_lookup$arity$2] (cljs.core.js:23845)
    at Function.eval [as cljs$core$IFn$_invoke$arity$2] (cljs.core.js:6641)
    at Object.eval [as cljs$core$IFn$_invoke$arity$1] (cljs.core.js:11321)
    at cljs$core$pr_writer (cljs.core.js:33105)
    at Object.cljs$core$pr_sequential_writer [as pr_sequential_writer] (cljs.core.js:32802)
    at Object.cljs$core$pr_writer_impl [as pr_writer_impl] (cljs.core.js:33011)
    at cljs$core$pr_writer (cljs.core.js:33113)
    at Object.cljs$core$pr_sequential_writer [as pr_sequential_writer] (cljs.core.js:32802)
    at Object.cljs$core$pr_writer_impl [as pr_writer_impl] (cljs.core.js:33011)
    at cljs$core$pr_writer (cljs.core.js:33113)
I googled, for the error, and it seems related to clojurescript, but I can't figure why. Any pointers?

dpsutton21:11:33

If you try (do (your form above) nil) does it work?

Carlo21:11:40

it does, and doesn't cause the error! But why?

dpsutton21:11:25

The error above had some stack traces in the printer. So it seemed like it was “working” but just blowing up printing the result in the repl

Carlo21:11:30

I see! Thanks a lot for explaining that!

Carlo21:11:21

and is writing (do MyForm nil) (or defining (silence MyForm) the best I can do here?

dpsutton21:11:55

You can’t print the value. But the value itself is fine. If you’re using the repl the p is killing you. If it’s just in regular code or not the return value of an expression if printed it’s fine

Carlo21:11:56

I see, thanks again 🙂

leif23:11:14

You know, looking into eval in clojurescript some more, is there any reason why find-ns-obj can't work in :target :bundle?

phronmophobic00:11:46

can’t bundlers make many types of transformations as well as add asynchrony when loading modules? it seems like either of those could potentially break find-ns-obj

leif00:11:13

I mean that's true if you want to eval code that interacts with an existing namespace.

leif00:11:54

But what if you wanted to have a sort of sandboxed evaluation where the evalled code can't interact with the bundled code?

phronmophobic01:11:37

i suppose there are situations where it might work. my guess is that’s it’s the type of thing where they’re explicitly not intending to offer support for that use case since it could potentially be a rabbit hole

leif01:11:07

I see. Sad. 😞

leif01:11:01

Okay, so it sounds like a sandboxed-eval isn't really possible with clojurescript. Thanks anyway. 😞

phronmophobic01:11:48

sand boxing and target bundle isn’t the only possible combination. what’s wrong with producing javascript using the normal target and using one of the available javascript sandboxing options?

phronmophobic02:11:23

if sand boxing is the primary goal, then i think that should be doable

leif03:11:12

@U7RJTCH6J I'm mostly using the bundle target for npm packages.

leif03:11:54

Although I have another possible approach. Would it be possible to run two clojurescript programs on the same page?

leif03:11:38

If so, then one could be build with bundle and the other the default target and then communicate through websockets or something like that.

phronmophobic03:11:27

i’m away from keyboard, but I assume there’s some set up that allows for using npm packages and having sandboxed clojure script eval in the browser.

phronmophobic03:11:53

have you tried shadow cljs? i’m not super familiar with its internals, but it’s integration with npm has been great in my experience and it looks like it support several targets, http://shadow-cljs.org

phronmophobic03:11:53

for sand boxing, i would use one of the tools that focuses on sandboxing js in the browser and using that for your js eval function

phronmophobic03:11:45

unless the sandboxing isn’t security critical, then I would just eval code in its own namespace

leif04:11:01

@U7RJTCH6J The sandboxing isn't security focused.

leif04:11:08

Its more just isolation.

leif04:11:23

And evaling it in its own namespace would 100% be enough, if I could. 😞

leif04:11:56

But since eval seems to directly call find-ns-obj it doesn't work with the bundle target. 😞

leif04:11:34

I have looked at shadow cljs, but IIRC its set to a fixed version of clojurescript

leif04:11:11

And so I'd be a bit dubious of it working since eval in older versions of clojurescript seemed to work just fine.

leif04:11:34

(Mostly because the *target* variable was pre-set to default, rather than bundle.

leif04:11:49

I'm not sure how that changed though.

leif04:11:58

Anyway, thanks for your help so far.

phronmophobic06:11:13

another option I would consider to ease the configuration issues is to have two separate js output builds. have one js output with target bundle that runs your application and does most of the work and have a second js build target that exports just the eval functionality that you need with the default target.

borkdude10:11:46

@U050G2TQJ if you need sandboxed eval in CLJS, you might want to look at sci