Fork me on GitHub
#clojurescript
<
2018-12-11
>
idiomancy00:12:36

is there some kind of.... like goog/object.call-this-objects-method-without-losing-the-`this`-context function?

idiomancy00:12:40

im trying to call the aws sdk and I'm getting hit with this.makeRequest is not a function even though I can clearly inspect said object and see said function

lilactown06:12:26

you can use .bind, .call or .apply

idiomancy06:12:49

hmm, interesting. the latter two I didn't know about. I ended up using the bind solution

currentoor00:12:33

how do i invoke a method on a javascript object by name?

currentoor00:12:38

in JS i would do foo[method]();

currentoor00:12:21

((goog.object/get foo "method")) isn’t working

darwin00:12:44

try ((goog.object/get js/window "alert"))

currentoor00:12:21

yeah that works but if i do the same with the Big.js library then i get this error

currentoor00:12:32

((aget x "lt") (n->big 4)))
TypeError: this.cmp is not a function

currentoor00:12:01

js/this is being changed i believe

darwin00:12:12

if the js lib uses this then it won’t work unless you are careful to preserve it, but that is more general problem

darwin00:12:48

(.call (goog.object/get foo "method") foo)

👍 4
darwin00:12:33

AFAIK clojurescript calls are with done this set to null

darwin00:12:37

you can look at generated js code in repl: (.toString (fn [] ((goog.object/get foo "method"))))

darwin00:12:56

it produces goog.object.get(cljs.user.foo,"method").call(null);

😮 4
john12:12:28

In Clojure, the java class hierarchy participates pretty seamlessly with the isa? hierarchy:

(derive java.util.Map ::collection)
(derive java.util.Collection ::collection)
(defmulti foo class)
(defmethod foo ::collection [c] :a-collection)
(defmethod foo String [s] :a-string)
(foo [])
:a-collection
(foo (java.util.HashMap.))
:a-collection
(foo "bar")
:a-string
How do we achieve a similar thing in ClojureScript?

john13:12:14

The closest thing I can come up with is:

(derive (type {}) ::collection)
(derive (type []) ::collection)
(defmulti foo type)
(defmethod foo ::collection [c] :a-collection)
(defmethod foo (type "") [c] :a-string)
(foo [])
:a-collection
(foo "bar")
:a-string
It's not quite the same though. I'd prefer to pass in type literals. And cljs types don't appear to ship with any ancestors out of the box.

john13:12:15

Or at least one's that automatically derive via isa?

Whiskas13:12:56

Has anyone here used some dashboard template built on ReactJs to create single page applications on ClojureScript?

john13:12:04

hmm, well this seems to work (defmethod foo js/String [c] :a-string)

john13:12:11

Still, does the docstring for isa? reflect the current implementation? ... via a JavaScript type inheritance relationship... The source doesn't appear to indicate the prototype tree is being walked atm https://cljs.github.io/api/cljs.core/isaQMARK

dnolen17:12:02

@dannyt yeah I don't think think the hierarchy stuff (around JS types) is well supported - not much usage, thus few reports

dnolen17:12:11

also wasn't clear how it should work

dnolen17:12:16

class? is meaningless

dnolen17:12:48

so it's not really possible to know if you have a type or not

dnolen17:12:34

ClojureScript's own types are tagged so we know - but you cannot do this for anything else

lilactown17:12:59

if I'm developing a library, what's the proper way to inform consumers to install npm deps for both figwheel-main, lein-figwheel and shadow-cljs?

lilactown17:12:28

e.g. I need consumers to make sure react & react-dom v16.7.0-alpha.2 is installed

richiardiandrea17:12:41

@lilactown you usually need a deps.cljs file containing :npm-deps on the classpath

richiardiandrea17:12:57

The compiler then should take care of the rest

dnolen17:12:30

note :npm-deps is a bit complected though - it pulls in deps but also gets the compiler to process those through Closure

dnolen17:12:54

so I would argue there's no current recommendable way to do this

lilactown17:12:32

I think that at least for react & react-dom, they're amenable to processing through gcc

dnolen17:12:59

you still need to provide some externs last I tried

dnolen17:12:01

just a few - but otherwise those libraries are Closure compatible

dnolen17:12:01

@lilactown still I can't say that I would recommend going down this route

dnolen17:12:01

making dependencies work consistently over the standard stuff and shadow-cljs is probably more trouble than it's worth at this time

richiardiandrea17:12:55

I have to say that I am compiling libraries with npm deps in shadow and never had a problem so far

richiardiandrea17:12:13

on node though, don't know browser, which might be different

john17:12:31

@dnolen Yeah, I didn't really understand how it would have worked either. Thanks for the clarification. I'm exploring isa? right now so I'll let you know if I notice anything salient.

David Pham18:12:12

Hello everyone :) I would like to develop a webapp mainly for data visual with user interaction. I wondered if anyone had advice? I am stuck at choosing my “styling” layer (bulma, material-design-lite or react-md)?

dnolen18:12:26

@richiardiandrea on Node we don't use Closure w/ :npm-deps so fewer issues

👍 4
lilactown19:12:34

it looks like reagent still uses cljsjs

lilactown19:12:04

I guess I just need to know how to tell consumers to install my library, which depends on react - should they use :npm-deps in their project? cljsjs?

aengelberg19:12:20

I'm trying to write a cross-compatible clj/cljs macro that uses let in its macroexpansion. But it turns out clojure.core/let potentially includes clojure.lang.PersistentHashMap/create in its macroexpansion (to support the "seq as map" use case), causing a warning on ClojureScript. Is there a way I can intelligently pick between clojure.core/let and cljs.core/let in my macro depending on which language i'm targeting?

aengelberg19:12:04

Alternative question, does this lack of let portability seem like a flaw in either of the underlying languages, or is the discrepancy in let implementations by design?

lilactown19:12:18

:thinking_face: I've never had an issue just doing `(let ...)

john19:12:22

I could have sworn I wrote a cross compatible macro with a let in it recently, with no issues. Is this an edge case?

aengelberg19:12:36

this only comes up if you use map-destructuring as one of the let bindings

aengelberg19:12:08

user=> (macroexpand `(let [{:keys [~'x]} {:x 1}]))
(let* [map__81766 {:x 1} map__81766 (if (clojure.core/seq? map__81766) (clojure.lang.PersistentHashMap/create (clojure.core/seq map__81766)) map__81766) x (clojure.core/get map__81766 :x)])

john19:12:15

Sounds like a bug

dnolen19:12:03

@aengelberg sounds like you're doing some manual stuff

dnolen19:12:07

this isn't a general issue

aengelberg19:12:22

manual stuff?

dnolen19:12:32

you just write a macro w/ let it will work

dnolen19:12:00

because clojure.core macros get aliased

dnolen19:12:51

people would have issues w/ macros a long time ago if this didn't just work

aengelberg19:12:09

you mean

`let => clojure.core/let
?

dnolen19:12:22

which is an alias for cljs.core/let

dnolen19:12:00

ClojureScript has it's own macroexpand

dnolen19:12:12

you can't use Clojure macroexpand to see what will happen

aengelberg19:12:38

oh I see, so you're saying I must be macroexpanding my let somewhere before it reaches cljs, otherwise it would work?

aengelberg19:12:03

ok thanks for the clue

aengelberg19:12:49

I thought I wasn't doing that, but will dig around

aengelberg19:12:59

ahhhh yeah I'm calling clojure.core/destructure during my macro logic

dnolen19:12:33

there's not a proper API, but it's pretty easy to know that you're in Clojure / ClojureScript by looking at &env

dnolen19:12:43

then you can choose differently

aengelberg19:12:18

good to know

idiomancy20:12:44

has anyone ever run into a situation with core.async where it just... doesn't block? Like, the takes are just succeeding without the put having occurred yet. It's just pulling empty values

idiomancy20:12:03

or.. it seems that way anyway

idiomancy20:12:50

(lambda + node + async) * various competing compiler options = madness!

john20:12:52

Sounds like a rough repro too :/

orestis20:12:28

Empty values? If it’s nil, it means the channel has been closed, afaik

john21:12:12

@neo2551 I've heard good things about bulma recently. In my experience, going with a pure css thing will interoperate more easily with react, unless the thing is made for react or you're a react life-cycle ranger.

dnolen21:12:00

@idiomancy as suggested, that would happen if the channel is closed

sova-soars-the-sora22:12:49

(sort-by not giving me expected results..

dpsutton22:12:39

how confident are you in your comparator? often bugs arise when the comparator is does not impose a total order

sova-soars-the-sora22:12:28

well i have a bunch of posts, i'm rendering them into html, i'm (sort-by'ing) the collection as it gets rendered... but no matter wha ti do the sequnce does not change

idiomancy22:12:18

@dnolen yeah, I got confused because the async/map function, upon receiving an initial value of nil (becuase the step before it had erred, ), it passed an empty sequence through to the next function rather than just closing.

sova-soars-the-sora22:12:08

anyway, i'm certain it's an easy fix, due to the list like nature of this recursive display... but i'll have to figure out exactly when to "sort-by"

sova-soars-the-sora22:12:30

does cljs use sort-by differently?

lilactown22:12:42

@sova it's hard to know what's wrong because we don't know how you're comparing them

lilactown22:12:12

AFAICT sort-by works the same as Clojure, but there might be something weird with the function you're using to compare them

idiomancy22:12:18

it also seems possible that the problem is your rendering, not your sorting

☝️ 8
sova-soars-the-sora22:12:19

buncha maps, comparing on a particular key

idiomancy22:12:41

if, for instance, you used a form 2 but didnt pass through the args to the inner function

sova-soars-the-sora22:12:40

(rum/defc render-item < rum/reactive show-fresh [pid]

  (let [post-coll   (rum/react posts) ;atom
        input-coll (rum/react input-state)
        cids (return-comment-ids pid)]
    ;(prn cids)
    (if (empty? (return-comment-ids pid))
      (let [noc-post  (first (filter  #(= pid (:id %)) post-coll))]
        [:div.nocomments {:id pid :class "genpost"}
         [:div.padleft {:on-click (fn [e] (do
                                         (.log js/console "Freshly selected: " pid)
                                         (.stopPropagation e)
                                         (swap! input-state assoc-in [:inputs 0 :selected-parent] pid)
                                         (swap! input-state assoc-in [:inputs 0 :selected-child] (return-comment-ids pid))))}
          [:div.item-contents.genpost {:class (cond (= pid (get-in @input-state [:inputs 0 :selected-parent])) "selectedParent"
                                            (some #(= % pid) (get-in @input-state [:inputs 0 :selected-child])) "selectedChild")} (:contents noc-post)
            [:div.item-author   (:author noc-post)]
            [:div.rate
              [:div.item-rate-doubleplus "++"]
              [:div.item-rate-plus "+"]
              [:div.item-rate-minus "-"]
              [:div.item-rating   (/ (:ratings-total noc-post) (:number-of-ratings noc-post))]]]]])
       ;lest the post has comments and needs more renders in pocket.
       (let [com-post (first (filter  #(= pid (:id %)) (sort-by #(/ (:ratings-total %) (:number-of-ratings %))  post-coll)))]
         [:div.hascomments {:id pid }
          [:div.padleft {:on-click (fn [e] (do
                                         (.log js/console "Freshly selected: " pid)
                                         (.stopPropagation e)
                                         (swap! input-state assoc-in [:inputs 0 :selected-parent] pid)
                                         (swap! input-state assoc-in [:inputs 0 :selected-child] (return-comment-ids pid))))}
           [:div.item-contents.genpost  {:class (cond (= pid (get-in @input-state [:inputs 0 :selected-parent])) "selectedParent"
                                              (some #(= % pid) (get-in @input-state [:inputs 0 :selected-child])) "selectedChild")} (:contents com-post)
             [:div.item-author (:author com-post)]
             [:div.rate
               [:div.item-rate-doubleplus "++"]
               [:div.item-rate-plus "+"]
               [:div.item-rate-minus "-"]
               [:div.item-rating   (/ (:ratings-total com-post) (:number-of-ratings com-post))]]]
           (map render-item cids)]]))))

sova-soars-the-sora22:12:16

two branches: if it has a comment print out the post and call again the fxn... if it has no comments just print the post

sova-soars-the-sora22:12:56

each post is just a map with {:contents "" :author "" :timestamp "" :number-of-ratings 2 :ratings-total 177}

sova-soars-the-sora22:12:18

the rendering works fine for showing indented branches of comments in the comment tree. but, i'd like to sort them by :ratings-total or the quotient of ratings-total and number-of-ratings. but anyway, no matter where i throw in a (sort-by :number-of-ratings ...) there's no change in the data on the page. despite a visible page refresh

lilactown23:12:10

you're talking about com-post here?

sova-soars-the-sora23:12:49

in this specific example yes

sova-soars-the-sora23:12:13

but i gotta make sure my data is covering this test case ... so standby pls ^_^

lilactown23:12:51

you can try doing it at the REPL and see if it behaves the way you expect

sova-soars-the-sora23:12:52

my comment-ids function looks like this, but i need to sort the returned comments by a key...

sova-soars-the-sora23:12:45

:comments is a sequence [ ]

sova-soars-the-sora23:12:13

how can i go from (44 22) to [44 22] ?

john23:12:23

Can you get the view to update via other means? I'm betting on @idiomancy's guess.

john23:12:11

You're re-render might not be triggering for some reason

sova-soars-the-sora23:12:37

maybe i need to sort the atom

sova-soars-the-sora23:12:42

and then it will do what i want

sova-soars-the-sora23:12:08

but i'm not certain how to sort it

john23:12:18

Yeah, or store the sorted result back in at another location and then render from there

john23:12:01

(another location in the same atom)

sova-soars-the-sora23:12:03

well dig this, i have a comment and it has children, and the children are now competing on rating, i have to check which one is higher before rendering, or just have the atom have the higher one first. it's a fun puzzle, since i'm building a tree by reference

john23:12:26

Yeah that's interesting. Does a user interaction somehow trigger the resort without altering the atom's state?

john23:12:54

I'm not too familiar with rum

sova-soars-the-sora23:12:38

rum is great, you just put > rum/reactive and (rum/react @posts) and it's more-or-less an observable that will trigger a ui update on changes to that atom.

john23:12:34

I'd think all views that depend on it would update on any change then, but rum may make less assumptions about what you want rendered, iirc, so you may have to do some stuff manually.

sova-soars-the-sora23:12:22

yes, the tricky part is how i'm storing my comments

sova-soars-the-sora23:12:40

i'm storing them as a list of references. and i just noticed that to "sort them" means to sort that little list of references in each post in the atom.

sova-soars-the-sora23:12:48

(let [sort-me-id 77
      spot  (first (first (filter #(= (:id (second %)) sort-me-id) (map-indexed vector @posts))))
      sorted-comments  (map :id
                         (sort-by :number-of-ratings >
                           (map get-post-by-id
                             (:comments (get-post-by-id sort-me-id)))))]
    (swap! posts assoc-in [spot :comments] sorted-comments ))

sova-soars-the-sora23:12:10

probably a dozen cleaner ways to do it