Fork me on GitHub
#clojurescript
<
2020-03-30
>
Bardia Pourvakil03:03:21

Anyone have any idea why I’m not able to access my namespaces in my CIDER nrepl session into my shadow-cljs project

dpsutton15:03:48

defmethod ends up as a deftype with a method table as an atom. Is it gross to (keys @(.-method-table my-method)) ?

dpsutton15:03:24

if i want to know the args for which there is a defmethod

joelsanchez15:03:12

isn't that methods?

dpsutton15:03:01

wow thanks! didn't know about that one

👍 4
Vishal Gautam16:03:45

has anyone used reitit routing library on the frontend

Spaceman16:03:44

Hi guys, what's the best way to handle stripe payments in the client side in a re-agent app?

Spaceman16:03:21

Like here, https://stripe.com/docs/payments/accept-a-payment-charges, there's a way to put a script tag in the html

Spaceman16:03:41

and then do

var stripe = Stripe('pk_test_sadljfdslafjsdalfjsdljfkjls');
var elements = stripe.elements();
in js. How to replicate this in clojurescript? When I do (.. Stripe 'pk_test_sadljfdslafjsdalfjsdljfkjls'), I get that Stripe isn't defined.

Michaël Salihi16:03:11

You can try: (Stripe. "pk_test_sadljfdslafjsdalfjsdljfkjls")

Michaël Salihi16:03:59

How do you require Stripe ?

Spaceman16:03:04

I just add a script tag in my index.html

Spaceman16:03:56

(Stripe. "sdfasfdsaashqerhq") doesn't work

Spaceman17:03:08

it says undeclared variable Stripe.

lilactown17:03:35

@pshar10 what compiler are you using?

lilactown17:03:07

you’ll need to configure externs for stripe

Spaceman17:03:12

How do I do that?

manutter5117:03:03

“Undeclared variable” sounds like it isn’t loading the js for Stripe at all, maybe you need to include a <script> tag in your enclosing HTML document? Or possibly use shadow-cljs.

lilactown17:03:14

there are many ways. you can try using cljsjs: https://github.com/cljsjs/packages/tree/master/stripe which involves adding a dependency in your deps.edn to cljsjs/stripe and then requiring it like:

[stripe :refer [Stripe]]
(I think that’s the right require, not sure)

Spaceman17:03:33

I don't know how to add a dependency in a deps.edn. I don't have that file in my project

lilactown17:03:38

FWIW, referring to global JS variables requires you to add js/ at the beginning of the symbol. js/window, js/document, etc. but in this case, it’s better to have the externs since it will help prevent errors when doing advanced optimizations

lilactown17:03:56

@pshar10 are you using leiningen? it would be project.clj then

Spaceman17:03:58

@lilactown I required it like so in my project.clj [cljsjs/stripe "3.0-0"]. I get "No such namespace: stripe, could not locate stripe.cljs, stripe.cljc, or JavaScript source providing "stripe"", where I used it [stripe :refer [Stripe]]

lilactown17:03:09

did you restart your compiler too?

👍 4
lilactown17:03:24

I’m not sure about the require, it’s hard to tell from cljsjs what the correct namespace is for externs

Spaceman17:03:27

I have a general question. How to import any js library in a clojurescript project (Figwheel) without using cljsjs? Like is there something as simple as doing npm install --save whatever?

dpsutton17:03:34

i think this is where shadow-cljs shines and actually fulfill's Clojure's promise of easy interop with the host language ecosystem

johnj17:03:10

how reliable is "externs inference" ? does it requires manual intervention occasionally?

lilactown17:03:44

I use shadow-cljs’ externs inference and it’s pretty good

johnj17:03:28

oh there are two competing impletations

Spaceman18:03:25

I'm okay with using js/Stripe which works. However, I have a problem with js promises: I'm trying to convert this js code:

stripe.createToken(card).then(function(result) {
    if (result.error) {
      // Inform the customer that there was an error.
      var errorElement = document.getElementById('card-errors');
      errorElement.textContent = result.error.message;
    } else {
      // Send the token to your server.
      stripeTokenHandler(result.token);
    }
And I have the following:
(go
     (let [result (<!
                   (.createToken stripe @(subscribe [:card-element]))
                   )]
       (prn "result is" result)
       ;; (if (.-error result)
       ;;   (.textContent (js/document.getElementById "card-errors") (.-message .-error result))
       ;;   (prn "response is" (js/stripeTokenHandler (.-token result)))
       ;;   )
       )
    )
   
But I get the error:

Spaceman18:03:39

No protocol method ReadPort.take! defined for type object: [object Promise]

dpsutton18:03:50

you're calling <! on a promise. .createToken returns a promise not a channel that you can take from

Spaceman18:03:21

I was conflating these concepts. How do I do the javascitip .then() part in cljs?

p-himik18:03:21

(.then promise callback).

jjttjj19:03:58

Is it possible to make a ratio or bigdec type as a library in cljs that plays nice with the rest of the number system (ie all arithmetic and comparisons work with regular numbers)?

p-himik21:03:16

Only if you use some custom functions instead of the built-in ones like +, -, and so on, and use them everywhere. Which means that this approach doesn't really scale beyond your own application code.

jaide19:03:22

Thought this would make for a convenient macro for this small side project. Howerver I can't get it to work. I get an Can't use qualified name as parameter error due to resolve and reject being qualified in the ns.

(defmacro promise
  "
  Example:

  (promise (resolve 5))
  (promise (reject  (js/Error. \"oops\")))
  "
  [body]
  `(js/Promise. (fn [resolve reject] ~body)))

Darrell19:03:43

Are resolve and reject functions or just indicators that the promise is being resolved/rejected?

jaide19:03:51

Pretty sure resolve and reject are functions

jaide19:03:16

The equivalent JS of the first example:

new Promise(function (resolve, reject) { 
  resolve(5);
});

Darrell19:03:35

Wouldn’t you want (fn [resolve & reject] ~body) since you wouldn’t be resolving and rejecting a the same time? (acknowledging this is unrelated to your original question)

jaide19:03:18

The default JS Promise constructor always provides a resolve and reject args to the function.

Darrell19:03:02

I see, thanks.

jaide19:03:46

(println (macroexpand '(p/promise
                        (resolve 5))))

;; =>

(new js/Promise
     (cljs.core/fn [cljs.core/resolve project.promise/reject]
       (resolve 5)))

dpsutton20:03:52

you need to quote those anaphoric symbols i believe

dpsutton20:03:14

sorry you want ~'

jaide20:03:30

Thanks! Just found the same solution recommended in clojuredocs defmacro examples

(defmacro promise
  "
  Example:

  (promise (resolve 5))
  (promise (reject  (js/Error. \"oops\")))
  "
  [body]
  `(js/Promise. (fn [~'resolve ~'reject] ~body)))

parens 4
Ben Hammond21:03:17

what is the state-of-the-art idiomatic way to work with JS Promises? (somehow) convert them into core.async Promise Channels? [funcool/promesa "4.0.0"] ? Plain ol' interop?

Chris O’Donnell21:03:57

I like to convert them to core async channels using https://github.com/wilkerlucio/wsscode-async

👍 4
Ben Hammond21:03:45

thanks will look at that

lilactown21:03:03

I wouldn’t use core.async just for promises. most of my apps haven’t used core.async so I just use interop

lilactown21:03:18

if your app already uses core.async, then wsscode-async seems nice

Chris O’Donnell21:03:48

I agree that interop is fine if you're not using core async elsewhere in the app 👍

Ben Hammond21:03:04

ooh yeah that looks pretty fluent

Ben Hammond21:03:11

thats very helpful

Ben Hammond21:03:08

I am using core.async anyway, for websocket comms

jaide22:03:00

Started drafting some macros over the weekend to smooth out interop a bit for a project using cljs + puppeteer. Came up with these, which may not be quite as helpful for your project but I'm interested in feedback if anything here is useful or if it only mirrors someone elese's work. https://gist.github.com/eccentric-j/1d84d332a8afc9dcc1dbb48309811407

👍 4
Jacob O'Bryant17:03:44

I use a macro that converts promises to channels, e.g.:

(go (prn (js<! (some-promise))))
https://github.com/jacobobryant/trident/blob/master/src/trident/util.cljc#L111

jaide00:04:23

Wow that's really slick! I was thinking about how to make a macro like p/let and p/try but athos clearly beat me to it 😄

lilactown21:03:49

I just use interop

👍 4
Mario C.23:03:23

I need to give certain input elements a datamask depending on the type of class it has. I am using Reagent and I am wondering how could I do this if I am using this https://github.com/RobinHerbots/Inputmask. Is there a way to apply this while creating the input component? Currently the way it is being done is calling (-> (js/jQuery ".hasDatePicker") (.inputmask "99/99/9999" (clj->js {:clearIncomplete true}))) on :component-did-update which is on a component that wraps a whole form element, that contains all the inputs. This doesn't seem to be the proper way of doing it.