reagent

A minimalistic ClojureScript interface to React.js http://reagent-project.github.io/
greensponge 2020-12-08T13:19:16.354600Z

Hello everyone, has anyone used https://github.com/ukrbublik/react-awesome-query-builder#usage or similarly (complex?) React components? I can't seem to get field values to work, everything renders fine EXCEPT the drop-down list values, which is empty no matter what I do, there are no errors and I'm not sure where I've made a mistake. Can someone point me to some Reagent docs on how to create this type of React component properly or can anyone see an issue in the code / recommend another way of doing this? P.S. I'm just trying to get it to work, so the code is not re-factored / is a bit uglier than usual. I've also tried not casting everything to JS with identical results.

(ns.slack-example 
  (:require [reagent.core :as r]
            ["react-awesome-query-builder" :refer (Query Builder BasicConfig Utils)]
            ["react-awesome-query-builder/lib/config/material" :default MaterialConfig])

(defn render-builder [^js props]
  (r/create-element "div"
                    #js {:className "query-builder-container"}
                    (r/create-element "div"
                                      #js {:className "query-builder"}
                                      (r/create-element Builder props))))

(def test-fields
     {:fields {:qty {:label "Qty"
                     :type "number"
                     :fieldSettings {:min 0}
                     :valueSources ["value"]
                     :preferWidgets ["number"]}}})

(def my-config
     (let [conjunctions (.-conjunctions MaterialConfig)
           operators (.-operators MaterialConfig)
           widgets (.-widgets MaterialConfig)
           types (.-types MaterialConfig)
           settings (.-settings MaterialConfig)
           fields (clj->js test-fields)]
       {:conjunctions conjunctions
        :operators operators
        :widgets widgets
        :types types
        :settings settings
        :fields fields}))

(def query-value (clj->js {:id (js-invoke Utils "uuid") :type "group"}))

;; Here I tried creating a Form-2 component, but nothing changed, I suspect I might be screwing up something in the state
(defn query-component [config]
  (let [state (r/atom {:tree (js-invoke Utils "checkTree" (js-invoke Utils "loadTree" query-value) config)
                       :config config})]
    (fn [config]
        [:> Query {:conjunctions (:conjunctions config)
                   :operators (:operators config)
                   :widgets (:widgets config)
                   :types (:types config)
                   :settings (:settings config)
                   :fields (:fields config)
                   :value (:tree @state)
                   :render-builder render-builder
                   :on-change (fn [^js immutable-tree ^js config]                           
                                (reset! state {:tree immutable-tree :config config}))}])))

;; Example of calling/rendering the component functions
[query-component my-config]

Shako Farhad 2020-12-08T13:19:31.355Z

Has anyone any experience with using Lottie in clojurescript and perhaps with reagent? Any quickstart guide for it?

p-himik 2020-12-08T13:59:38.355100Z

The code below works for me just fine. Note that it has a lot of unnecessary JS<->CLJS data conversion, but that's only because I was lazy. I didn't really try to figure out what's wrong with your code because, as you said it yourself, it's not cleaned up. I could look into it if you create a proper MRE.

(ns clj-playground.react-awesome-query-builder
  (:require [reagent.core :as reagent]
            ["react-awesome-query-builder" :refer [Query Builder BasicConfig Utils]]
            ["react-awesome-query-builder/lib/config/material" :default MaterialConfig]))

(def initial-config (assoc (js-&gt;clj MaterialConfig)
                      :fields {:qty          {:label         "Qty"
                                              :type          "number"
                                              :fieldSettings {:min 0}
                                              :valueSources  ["value"]
                                              :preferWidgets ["number"]}
                               :price        {:label         "Price"
                                              :type          "number"
                                              :fieldSettings {:min 10, :max 100}
                                              :valueSources  ["value"]
                                              :preferWidgets ["slider", "rangeslider"]}
                               :color        {:label         "Color"
                                              :type          "select"
                                              :fieldSettings {:listValues [{:value "yellow", :title "Yellow"}
                                                                           {:value "green", :title "Green"}
                                                                           {:value "orange", :title "Orange"}]}
                                              :valueSources  ["value"]}
                               :is_promotion {:label        "Promo?"
                                              :type         "boolean"
                                              :operators    ["equal"]
                                              :valueSources ["value"]}}))

(def initial-query-value {:id   (.uuid Utils)
                          :type "group"})

(defn render-builder [props]
  (reagent/as-element
    [:div {:class :query-builder-container
           :style {:padding 10}}
     [:div {:class [:query-builder :qb-lite]}
      [:&gt; Builder (js-&gt;clj props)]]]))

(defn render-result [tree config]
  (let [config (clj-&gt;js config)]
    [:div {:class :query-builder-result}
     [:div "Query string: " [:pre (js/JSON.stringify (.queryString Utils tree config))]]
     [:div "MongoDb query: " [:pre (js/JSON.stringify (.mongodbFormat Utils tree config))]]
     [:div "SQL where: " [:pre (js/JSON.stringify (.sqlFormat Utils tree config))]]
     [:div "JsonLogic: " [:pre (js/JSON.stringify (.jsonLogicFormat Utils tree config))]]]))

(defn demo-query-builder []
  (reagent/with-let [tree (reagent/atom (.checkTree Utils
                                                    (.loadTree Utils (clj-&gt;js initial-query-value))
                                                    (clj-&gt;js initial-config)))
                     config (reagent/atom initial-config)
                     on-change (fn [new-tree new-config]
                                 (reset! tree new-tree)
                                 (reset! config (js-&gt;clj new-config)))]
    [:div
     [:&gt; Query (assoc @config
                 :value @tree
                 :on-change on-change
                 :render-builder render-builder)]
     [render-result @tree @config]]))

p-himik 2020-12-08T14:00:02.355300Z

^ that example is ported from usage directly, more or less.

greensponge 2020-12-08T14:15:19.355500Z

As always thank you for your quick and helpful responses @p-himik! I will compare this code to mine and figure out the difference. Pardon my laziness with the example code, I'll be sure to spend more time creating easy-to-reproduce examples next time. 👍

👍 1