Fork me on GitHub
Grigory Shepelev07:10:24

Any help? The reply is not helpful. I am using re-frame default template with in-build hiccup and I want to use google-material components in my app in idiomatic style:

(ns re-frame-blog.views
  [re-frame.core :as re-frame]
  [re-frame-blog.subs :as subs]
  [material-components-web :as material]))
(defn home-panel []
(let [name (re-frame/subscribe [::subs/name])]
   [:h1 (str "Hello from " @name ". This is the Home Page.")]
   [material/card ;; say I want to use material card here
    [:p "text"]]
    [:a {:href "#/about"}
     "go to About Page"]]]))


MDC Web is a library that relies on the existing DOM. It's not a great fit for React (which Reagent uses. Which, in turn, is used by re-frame). Because of that (and unless there's some documentation that I can't find), you cannot use it in Hiccup directly as in your example. You have to either use refs everywhere and manually create all the components just like in the example in the documentation, or you have to follow the other example where they just create the DOM with the necessary data attributes and just let MDC to automagically patch those DOM elements.


Have you ever used jQuery? Well, MDC Web is exactly like that.


You might be interested in this, which appears to bring MDC Web closer to React:

Grigory Shepelev07:10:56

Yes, I used JQ few times. I left behind state of modern webdev for couple years.


Alternatively, you can use a library that was intended to work with React in the first place, like Material UI for example.


jQuery is not used with React in general. React is about mutating state that's separate from the components. jQuery is about mutating the DOM directly.

Grigory Shepelev07:10:52

So. If I use react (that re-frame does implicitly) I need to look for "react-builds" of css libs?


You need to look for something that can be used with React. You can use MDC Web with React. But it's either painful or requires an additional wrapper.

Grigory Shepelev07:10:07

Ok. Thanks. Clojurescript - js interop is very complicated IMHO. Especially if I had no experience with react. I'm just trying to figure the stuff out.

Grigory Shepelev07:10:48

So. Given that I installed rmwc with npm. How do I use it with re-frame and hiccup? As simple as I wrote? Do I have to add something in project.cljs ?


"Clojurescript - js interop is very complicated IMHO" - but your issue has absolutely nothing to do with CLJS/JS interop. JS interop is quite simple, in fact. You can access JS objects from CLJS just fine, and you can export any CLJS symbol to JS just fine as well.


The section "Creating Reagent "Components" from React Components" is of extra interest to you. But the whole document is still a must. Including the links at the bottom, especially since they contain examples.

Grigory Shepelev08:10:44

Having read that I still don't understand how do I call a component?

(ns re-frame-blog.views
  [re-frame.core :as re-frame]
  [re-frame-blog.subs :as subs]
  ["rmwc" :as material]))

(defn home-panel []
(let [name (re-frame/subscribe [::subs/name])]
   [:h1 (str "Hello from " @name ". This is the Home Page.")]
   (material/card [:p "text"])
    [:a {:href "#/about"}
     "go to About Page"]]]))

Grigory Shepelev08:10:00

How do I access card for example?


First of all, what do you mean by "access"?

Grigory Shepelev08:10:08

I had some previous experience with VueJs about 1.5 y. ago. After webpack setup I could just import card in ES2015 style on top and then just use <card> ... </card>


I see. ["rmwc" :refer [Card]]. Better yet, ["@rmwc/card" :refer [Card]] to avoid pulling the whole library when you need just Card.


Note that I did check those :require vectors just in case, but they both are just direct translation of the rmwc documentation using that table in the shadow-cljs user's guide.


And then use it as [:> Card {...} ...], just as Reagent documentation says.

Grigory Shepelev09:10:57

Thnx. I will try in 15-10 minutes.

Grigory Shepelev11:10:28

Now I can see with element inspection (in Browser) that it uses the proper classes and stuff when I call elements like that: [:> Card {..} ...] Thanks. But it doesn't use styles from material design.

Grigory Shepelev11:10:03

Do I have to use webpack?


No. You can include CSS directly via HTML or some CLJS code (there are libraries for that).

Grigory Shepelev11:10:16

I want it with cljs.


Well, then you will have to find a library that can include CSS directly via code. I don't know of any offhand.

Grigory Shepelev12:10:15

re-frame has this one

:garden {:builds [{:id           "screen"
                     :source-paths ["src/clj"]
                     :stylesheet   re-frame-blog.css/screen
                     :compiler     {:output-to     "resources/public/css/screen.css"
                                    :pretty-print? true}}]}

Grigory Shepelev12:10:13

As far as I got this handles the css. I should add "/node_modules/material-components-web/dist" to :source-paths and something to :stylesheet. What exactly.


TBH, I feel like on your "road to CLJS enlightenment" you have skipped quite a few steps and now it creates a lot of confusion. re-frame is a state management library. It has nothing to do with CSS. The snipped you provided above is handled by some build tool apparently - I don't know what. But it uses the :garden keyword, which hints that it uses this library: The library by itself doesn't embed CSS in your page - it just renders CSS strings. OK, seems that you're using the re-frame template. IMO this is pretty much the worst way to learn CLJS simply because it not just allows you to skip steps but it actually forces you to. My advice: put MDC Web aside for now, build a small app without any libraries. Add some simple CLJS lib to it. Add some simple NPM lib to it. Gradually increase the complexity while making sure that you understand what's going on at each step.


BTW the above :garden configuration just tells lein-garden plugin to compile whatever Garden CSS definitions are in re-frame-blog.css/screen into regular CSS and save the result into "resources/public/css/screen.css". It doesn't embed CSS into your page automatically. You still have to include it in your HTML somehow. Which the template does right here:

Kasey Speakman08:10:53

Ok, I feel like I am taking crazy pills. I'm using comp with partials to define a function in ClojureScript. (It's an experiment, not something I want to do routinely.) If I immediately invoke the function it works. But if I assign a name to it with def and then try to invoke that with an argument it always just returns whatever is passed into it. Basically becomes identity.

(defn test- [trait f value]
  (if-some [value (f value)]
      {::error trait}))

(defn test-and- [trait f value]
  (if (contains? value ::error)
    (test- trait f value)))

((comp (partial test-and- :keyword keyword)
       (partial test- :required not-empty)) "")
=> #:myns.core{:error :required}

((comp (partial test-and- :keyword keyword)
       (partial test- :required not-empty)) "asdf")
=> :asdf

(def tmpf (comp (partial test-and- :keyword keyword)
                (partial test- :required not-empty))

(tmpf "")
=> ""

Kasey Speakman08:10:50

Nvm, was missing a paren


Is there a JS of CLJS library which implements a widget similar to "Apply labels to this issue" in Github?


I suddenly started getting 100s of Cannot infer target type in expression (. (. obj -userData) -tile) in my project. it wasn't like this yesterday when I left it. anyone who has a clue as to what might have happened?


Did you maybe add (set! *warn-on-infer* true) somewhere in your code?


if you set that to false it should stop giving you the warning. But probably you wanna leave it on, and actually fix the cause. Google Closure Compiler sometimes does the "wrong thing" and these warnings can help you pinpoint where things are funky


nope, I haven't set it to true as far as I can see... when the issue does arise, how do I figure out what to do about it?


thanks, I'll take a look


(js/alert "foo") is working fine but not (js/console.log "foo"), I tried it in two browsers… thoughts about how to troubleshoot this? I get nil as a response to the log statement, if that’s useful.


did you open up the browser console?


I’m evaluating the statement inline… l also tried it in the Emacs cljs REPL.


By the way, I had an awesome time last night and this morning building a simple site interactively… so cool… all because of your help getting me over the setup hurdle. It’s so cool when this all works!


i'm glad you're up and running!


so sweet, the approach to setting up a project in the talk… I prefer not using lein templates if I can…


is there a way to connect emacs to the repl? I used to use cider-connect to nrepl.


In the talk, for interactivity, it looks like you use the terminal prompt repl… not sure. I did the non-repl version and quickly had a webpage.


correct. the talk was a lightning talk so i had 5 minutes. didn't want to get into editor interactivity


oh c’mon… you could have taught them emacs in 5 minutes!


oh. in this case i did it just to be quick. if you cider-jack-in-cljs your repl will be connected


Who is it at Cognitect who does all their development at the repl prompt?


ok, trying that now.


omg, it all works.


do you have multiple browser tabs open?


I do… but I solved it!


I guess you have to select the info button on the left in Chrome dev tools… they have you select your filters there now.


in other words, I was filtering it out (but the options are no longer at the top where I used to expect them).

Ronny Li19:10:08

Hi does anyone know how to resolve this figwheel error?

[Figwheel] Successfully compiled build dev to "target/public/cljs-out/dev/main.js" in 35.941 seconds.
[Figwheel] Bundling: npx webpack --mode=development target/public/cljs-out/dev/main.js -o target/public/cljs-out/dev/main_bundle.js
[Figwheel:SEVERE] Bundling command failed
asset main.js 644 bytes [compared for emit] (name: main)

ERROR in main
Module not found: Error: Can't resolve 'target/public/cljs-out/dev/main.js' in '/Users/abc/demo'

webpack 5.1.2 compiled with 1 error in 47 ms
I'm following the Figwheel instructions for and my dev.cljs.edn file looks like this:
 :main demo.core
 :target :bundle
 :bundle-cmd {:none ["npx" "webpack" "--mode=development" :output-to "-o" :final-output-to]}
Thanks in advance!


If no one answered this yet, there is an open issue for this and I believe the solutions were outlined recently in #figwheel-main

Faiz Halde21:10:03

I’m curious, what makes the execution of the following two approaches behave so differently? (reagent)

(defn dummy
  (rdbg/log "hi")
  (let [num (r/atom 1)
        _ (js/setTimeout #(reset! num 2))]
    (rdbg/log "bye")
    [:pre @num]))

(defn dummy
  (rdbg/log "hi")
  (let [num (r/atom 1)
        _ (js/setTimeout #(reset! num 2))]
    (fn []
      (rdbg/log "bye")
      [:pre @num])))
in the 1st case, i had missed out on returning a function (form 1 component) .. and what i saw on my console logs was continous “hi/bye” logs suggesting the component is getting rendered again and again (the ratom was updated in a settimeout yes, but it is done for the 2nd example as well) the 2nd one worked perfectly fine (as it should) .. what exactly is happening under the hood?


When you return a function from a reagent component, on subsequent renders it will only run the inner function


This allows you to construct objects (like an atom) when the component initially mounts, which will be kept alive and referenced until the component unmounts


Without this, like in your first case, it will construct a new atom every render, which will always contain the initial state

Faiz Halde21:10:02

ohh, so if a function returns a hiccup then that function is the renderer. and since i updated the ratom, reagent reran the “dummy” function (which is the renderer because i returned a hiccup and not a function)

Faiz Halde21:10:23

need to dig more into the reagent interpreter now!

Faiz Halde21:10:00

that explains why the continuous logs

Faiz Halde21:10:07

hi, i’ve been scratching my head trying to implement the following (finally got something working but was wondering if there’s a better way) i have a parent-child component hierarchy, and there’s an IntersectionObserver that has to be initialized with the parent DOM element (so i place this in the ref callback of the parent). Now, I need to store this observer in a atom/ratom/some local state basically, so whenever child components mount, their ref callback runs and uses this observer to register themselves. but given the way react mounts component hierarchy (child first parent last), the ref callback of child sees the observer as nil (default) (because the parent ref callback hasn’t been called yet, so (. @observer observe dom)) will fail)

(defn log-viewer
  (let [observer (r/atom nil)
        nums (r/atom (range 30))] ;; ignore the nums
    (fn []
      [:div {:ref (fn [dom]
                    (if-not dom
                      (when @observer
                        (. @observer disconnect))
                      (reset! observer
                               {:root dom
                                :threshold 1}))))}
       (when @observer
         (for [x @nums]
           ^{:key x} [:pre {:ref (fn [dom]
                                   (when dom
                                     (. @observer observe dom)))} x]))])))
right now as a workaround(?) i used a ratom and put the childs within a when @observer condition. but i’m curious to know if there is a better way


This looks like a normal solution to me. Alternatively, you can store children refs at the level of the parent component right along observer in another atom (no need for ratom in this case) and just iterate over them and call .observe @observer on each in the parent's ref.