Fork me on GitHub
#clojurescript
<
2021-09-14
>
jussi09:09:46

Hi, I'm trying to use Victory chart library from a simple Reagent setup (shadow-cljs + reagent) for learning purposes. All is fine and dandy, but brush and zoom example has caused some trouble. it seems that the zoom-component needs a callback but I'm struggling to get it to work. Charts render nicely but trying to zoom in causes the following error Uncaught TypeError: f.call is not a function. What am I missing in cljs <-> js interop? I've also tried r/adapt-react-class to no avail. How does one handle callbacks in these cases?

(defn set-zoom-domain [domain]
  (swap! app-state update-in [:zoomDomain] domain))

(defn zoom-container []
  (r/create-element VictoryZoomContainer #js{:zoomDimension "x"
                                             :zoomDomain (get @app-state :zoomDomain)
                                             :onZoomDomainChange set-zoom-domain}))

(defn get-brush-container []
  (r/create-element  VictoryBrushContainer #js{:brushDimension "x"
                                               :brushDomain (get @app-state :zoomDomain)
                                               :onBrushDomainChange set-zoom-domain}))

jussi10:09:27

Passing a cljs function in js data structure does not seem to work.

p-himik10:09:23

CLJS functions are JS functions, so that's not the problem here.

p-himik10:09:19

Can you provide the rest of the code?

jussi10:09:52

(ns app.views
  (:require [app.state :refer [app-state]]
            [reagent.core :as r]
            ["moment" :as moment]
            ["victory" :refer [VictoryBar
                               VictoryChart
                               VictoryZoomContainer
                               VictoryLine
                               VictoryAxis
                               VictoryBrushContainer
                               VictoryLabel
                               VictoryTooltip]]))

(def data2 [{:co2ekv 14 :date  (moment "2021-09-01")}
            {:co2ekv 24 :date  (moment "2021-09-02")}
            {:co2ekv 34 :date  (moment "2021-09-03")}
            {:co2ekv 44 :date  (moment "2021-09-04")}
            {:co2ekv 16 :date  (moment "2021-09-05")}
            {:co2ekv 11 :date  (moment "2021-09-06")}
            {:co2ekv 17 :date  (moment "2021-09-07")}
            {:co2ekv 88 :date  (moment "2021-09-08")}
            {:co2ekv 12 :date  (moment "2021-09-09")}
            {:co2ekv 21 :date  (moment "2021-09-10")}
            {:co2ekv 44 :date  (moment "2021-09-11")}
            {:co2ekv 32 :date  (moment "2021-09-12")}
            {:co2ekv 33 :date  (moment "2021-09-13")}
            {:co2ekv 45 :date  (moment "2021-09-14")}
            {:co2ekv 145 :date (moment "2021-09-15")}
            {:co2ekv 55 :date  (moment "2021-09-16")}
            {:co2ekv 18 :date  (moment "2021-09-17")}
            {:co2ekv 77 :date  (moment "2021-09-18")}
            {:co2ekv 67 :date  (moment "2021-09-19")}
            {:co2ekv 56 :date  (moment "2021-09-21")}
            {:co2ekv 23 :date  (moment "2021-09-22")}
            {:co2ekv 74 :date  (moment "2021-09-23")}
            {:co2ekv 123 :date (moment "2021-09-24")}])

(defn header
  []
  [:div
   [:h1 "A template for reagent apps"]])

(defn set-zoom-domain [domain]
  (swap! app-state update-in [:zoomDomain] domain))

(defn zoom-container []
  (r/create-element VictoryZoomContainer #js{:zoomDimension "x"
                                             :zoomDomain (get @app-state :zoomDomain)
                                             :onZoomDomainChange set-zoom-domain}))

(defn get-brush-container []
  (r/create-element  VictoryBrushContainer #js{:brushDimension "x"
                                               :brushDomain (get @app-state :zoomDomain)
                                               :onBrushDomainChange set-zoom-domain}))

(defn chart [_]
  (r/create-class
   {:component-did-mount (fn [_ _]
                           (swap! app-state update-in [:zoomDomain]
                                  {:x [(moment "2021-09-04"), (moment "2021-09-06")]}))
    :render (fn []
              [:div
               [:> VictoryChart {:scale {:x "time"}
                                 :containerComponent (zoom-container)}
                [:> VictoryLine {:style {:data {:stroke "tomato"}}
                                 :data data2
                                 :x :date
                                 :y :co2ekv}]]

               [:> VictoryChart {:scale {:x "time"} ; Zoom chart
                                 :height 100
                                 :containerComponent (get-brush-container)}
                [:> VictoryAxis {:tickFormat (fn [tick]
                                               (. (moment tick) format "YYYY-MM-DD"))}]
                [:> VictoryLine {:style {:data {:stroke "tomato"}}
                                 :data data2
                                 :x :date
                                 :y :co2ekv}]]])}))

(defn app []
  [:div
   [header]
   [chart]])

p-himik10:09:42

Two things I can say without running it myself: • Assuming app-state is a Reagent atom and not a regular atom, when you change it, the whole chart will be re-rendered. Can't really tell if that's what you want, maybe it doesn't matter • In :component-did-mount, you swap in some CLJS data into the state that you later on use in r/create-element - that shouldn't work because I imagine the plotting library expects a JS object and not a CLJS map. #js is a reader tag - it creates a JS object out of the outer form and at compile time, so it's not recursive. You have to use either JS data in the first place or clj-js to deeply convert the data at runtime

jussi10:09:23

Thanks, I'll check'em both.

lassemaatta10:09:26

I may be wrong, but do those calls to swap! look ok? You're using update-in but supplying a datastructure instead of a function? did you mean to use assoc-in?

p-himik10:09:55

Good catch! Didn't notice that.

p-himik10:09:30

Also, just in case, you can use assoc instead of assoc-in if there's only one element in the vector.

jussi10:09:49

> I may be wrong, but do those calls to `swap!` look ok? You're using `update-in` but supplying a datastructure instead of a function? did you mean to use assoc-in? picard-facepalm

jussi10:09:04

It works now. Thanks @U0178V2SLAY 🎉

👍 2
jussi10:09:46

Head, meet concrete. 😄

maverick10:09:31

How can I use quick filter of ag-grid in clojurescript ?

p-himik10:09:08

Just like with any other of the plethora of JS libraries when you want to use them in your CLJS code. Get JS code and convert it to CLJS code using interop, documentation for whatever relevant CLJS libraries you might be using (like Reagent), and common sense.

maverick12:09:39

I have defined my grid options in cljs as (def grid-options {"columnDefs" colDefs "rowData" rowData "defaultColDef" {:sortable true } "suppressHorizontalScroll" false "rowSelection" "single" "pagination" true "paginationPageSize" 10 "rowStyle" {:background "lightgrey" }})

maverick12:09:33

I have my search input as

[:input.input {:class "search-input"
               :value @search-text
               :type "text" :placeholder "Search..."
               :on-change #(.. js/grid-options
                              api
                              setQuickFilter (@search-text))
           
               }]

maverick12:09:15

How do I make it work ?

p-himik12:09:05

At the very least, your JS-CLJS interop in :on-change is wrong.

maverick12:09:19

Is this the correct way ?

:on-change #(.. grid-options api (setQuickFilter (-> % .-target .-value)))

p-himik12:09:48

This would call api as a function. You have to add - in front of it.

Flawless12:09:57

Hi all! How can I reconnect to the running cljs build from clj using figwheel-main without rebooting whole repl?

souenzzo12:09:25

take a look at this https://github.com/bhauman/figwheel-repl you will first start a normal clj repl then you can • start a figwheel server • start a fighweel build • connect to a figwheel client • disconnect • connecto to another client ...

Muhammad Hamza Chippa20:09:24

any idea what this function is doing, maybe it is adding value to the atom, but it is not called in the program still creating impact

maverick21:09:18

I am trying to close the modal inside callback function of http call. But it is not doing anything. Here is the code

maverick21:09:20

(a-com/post-data data (fn [response] (println response) (reset! show-modal false) (println @show-modal) ))

David Vujic10:09:02

Without knowing how your code base looks like, I’m guessing that you are using Reagent. It might be that you are using the built in clojure atom, and not reagent/atom ? That may be the reason why React doesn’t trigger a re-render for your modal.

maverick11:09:49

@U018VMC8T0W I am using reagent/atom only

David Vujic11:09:18

What would happen if you run your code in the REPL? (reset! show-modal false)?

maverick15:09:28

It is working now. THanks