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
(:require
[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])]
[:div
[:h1 (str "Hello from " @name ". This is the Home Page.")]
[material/card ;; say I want to use material card here
[:p "text"]]
[:div
[: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: https://github.com/jamesmfriedman/rmwc
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.
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.
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.
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.
This link is still relevant if you still use shadow-cljs: https://shadow-cljs.github.io/docs/UsersGuide.html#_using_npm_packages You also need to read this: https://github.com/reagent-project/reagent/blob/master/doc/InteropWithReact.md
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.
Ok, I feel like I am taking crazy pills. I'm using comp
with partial
s 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)]
value
{::error trait}))
(defn test-and- [trait f value]
(if (contains? value ::error)
value
(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 "")
=> ""
Nvm, was missing a paren
Having read that I still don't understand how do I call a component?
(ns re-frame-blog.views
(:require
[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])]
[:div
[:h1 (str "Hello from " @name ". This is the Home Page.")]
(material/card [:p "text"])
[:div
[:a {:href "#/about"}
"go to About Page"]]]))
How do I access card for example?
First of all, what do you mean by "access"?
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.
Thnx. I will try in 15-10 minutes.
Is there a JS of CLJS library which implements a widget similar to "Apply labels to this issue" in Github?
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.
Have you read the page at https://rmwc.io/installation?
Do I have to use webpack?
No. You can include CSS directly via HTML or some CLJS code (there are libraries for that).
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.
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}}]}
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: https://github.com/noprompt/garden
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: https://github.com/day8/re-frame-template/blob/master/src/leiningen/new/re_frame/resources/public/index.html#L11
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?
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?
here's some links: - https://clojurescript.org/guides/externs - https://shadow-cljs.github.io/docs/UsersGuide.html#externs - https://figwheel.org/docs/advanced_compile.html - https://code.thheller.com/blog/shadow-cljs/2017/11/06/improved-externs-inference.html
thanks, I'll take a look
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
(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 did…
I’m evaluating the statement inline… l also tried it in the Emacs cljs REPL.
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).
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!
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 https://figwheel.org/docs/npm.html 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
Thanks! Copying the link to the solution here for others: https://clojurians.slack.com/archives/CALJ3BFLP/p1603126703062600?thread_ts=1603113368.056000&cid=CALJ3BFLP
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
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)
need to dig more into the reagent interpreter now!
thanks
that explains why the continuous logs
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
(js/IntersectionObserver.
rdbg/log
{: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 wayso 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
SWEET!
Who is it at Cognitect who does all their development at the repl prompt?
Jedi.
ok, trying that now.
omg, it all works.