reagent

A minimalistic ClojureScript interface to React.js http://reagent-project.github.io/
2020-10-27T01:43:09.108900Z

Good morning I am trying to ue a small wrapper function in reagent/re-frame to generate bootstrap/hiccup vecs. An example for a bootstrap column would be:

(defn col [{:keys [md]}. & children]
  [:div {:class (class-name (if md (str "col-md-" md) "col"))}
    children])
Used like
[col {} [:div "hi"]]
What happens in this example is that [:div "hi"] is captured by the [& children] in the params vector of col and converted to [[:div "hi"]] which is well and good, but reagent complains about this
Warning: Every element in a seq should have a unique :key
So, ok, no worries, I can avoid the error by calling col as
[col {} ^{:key "hi"} [:div "hi"]]
And the error goes away. I'm not crazy about this however because I have to pepper these metadata declarations around my code, even when a col has only one child. So my question is: Can col be rewritten to set the metadata on the children , avoiding the need to do so in the calling code. I haven't been able to get a working example.

phronmophobic 2020-10-27T01:51:43.109100Z

two options come to mind: 1. use into. I think this will get rid of the warnings when there's one child

(defn col [{:keys [md]} & children]
  (into [:div {:class (class-name (if md (str "col-md-" md) "col"))}]
        children))
2. provide some way to automatically derive a key. This example just uses the index, but you derive a key from some part of the children passed in
(defn col [{:keys [md]} & children]
  [:div {:class (class-name (if md (str "col-md-" md) "col"))}
        (map #(with-meta %1 {:key %2}) children (range))])

2💯
2020-10-27T02:05:26.109800Z

great response, thanks @smith.adriane

Александр Стоянов 2020-10-27T03:44:26.110500Z

Hello! I'm learning clojurescript now and have some problem: (def click-count (atom 0)) (defn b [] [:div "The atom " [:code "click-count"] " has value: " @click-count ". " [:input {:type "button" :value "Click me!" :on-click #(swap! click-count inc)}]]) in `main-panel`: (b) So that's almost work. I have button on my page but it doesn't refresh. First value is 0 and when i click on button value don't changes. It changes only when i clicked some times then re-build it and it shows quantity of clicks. So what i should do to refresh it without re-building?

Lucy Wang 2020-10-27T06:29:09.111500Z

1. you should use reagent.core/atom instead of clojure.core/atom 2. use [b] instead of (b)

1☝️
Александр Стоянов 2020-10-27T07:53:32.113Z

How to get data from input?

greensponge 2020-10-27T08:40:06.113100Z

To complete this answer for possible future readers, this was the missing piece of the puzzle and it ended up working perfectly when I had time to try it today (although as stated above, it would be even better to return the correct data response directly):

(.successCallback ^js params (clj->js (:rows (:body response))) (clj->js (:lastRow (:body response)))))))
For reference, the above ag-grid call is equivalent to this in JS:
params.successCallback(rows, lastRow);
Thanks again, @p-himik!

Lu 2020-10-27T10:09:24.114600Z

@mister.stoyanov13 To get data from a text input you want to use the :on-change handler. The event will be passed as a parameter in the callback function. Remember to use js interop when dealing with the event object, as it is a JS object in fact. A basic example is this:

(def state (r/atom {:input-value ""}))

(defn foo []
  [:input
   {:value (:input-value @state)
    :on-change (fn [js-event]
                 (swap! state assoc :input-value (-> js-event .-target .-value)))}])

Lu 2020-10-27T10:16:38.116500Z

Notice that if you want to get any information about the button input i.e. its value, you can similarly use (-> js-event .-target .-value) in its on-click callback

Christopher Stone 2020-10-27T13:58:54.127200Z

Hi Clojurians, I am relatively new to using reagent and have reached a bit of a stumbling block, I have searched for an answer for a few months now, trying to find a code example but keep being led back to the reagent docs that do not have an answer to my problem... I am trying to display a map using leaflet using adapt-react-class and have made some components that work with one another to display a map with various markers, collections of markers and geometry... the problem I am having is that I have no idea how to access methods on the adapted react class to add things to the map after the initial creation of the map, specifically using the Map.addTo() method... how do I access methods on an adapt(ed)-react-class, any help would be greatly appreciated

Lu 2020-10-27T14:20:27.128100Z

You can store your instance in an atom and refer to it when you want to call methods.. to give you an example:

(defn my-leaflet
  []
  (let [leaflet-state (atom nil)]
    (r/create-class
     {:component-did-mount
      (fn [props]
        (reset! leaflet-state (.setView (js/L.map (r/dom-node props)
                                                  #js {:zoomControl false})
                                        [50 50] 3)))
      :reagent-render
      (fn []
        [:div.leaflet-picture])})))

Christopher Stone 2020-10-27T15:36:30.139900Z

Thanks Lu for replying so quickly, just a couple of questions, In the code snippet you sent me I'm assuming that its a r/atom that I would use, is that right? can you please clarify... I am using react-leaflet, lifted from https://github.com/metosin/komponentit/blob/master/example-src/cljs/example/map.cljs. I am also using shadow-cljs and am not sure if I need to place the the react-leaflet dependancy string in the shadow-cljs.edn file or if its okay to just use "yarn add" (the latter is the method we used)... at the start of the file you will see that he setup a few global defs that break up the component parts and use them later in the code in one larger component... how could I achieve what I asked earlier in this situation? Thanks again

valtteri 2020-10-27T15:54:01.144800Z

React-leaflet is a declarative wrapper around imperative leaflet api. You don’t (usually) call any leaflet functions to make changes. Instead you create react components that describe what elements, content and functionality the map should have. Check react-leaflet docs for examples https://react-leaflet.js.org/docs/en/intro.html

valtteri 2020-10-27T15:55:05.145900Z

And yes, you can install react-leaflet from npm