This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-06-15
Channels
- # babashka (41)
- # beginners (47)
- # calva (7)
- # cider (5)
- # cljsrn (2)
- # clojure (38)
- # clojure-europe (74)
- # clojure-nl (2)
- # clojure-spec (1)
- # clojure-uk (38)
- # clojurescript (42)
- # component (30)
- # core-async (2)
- # cryogen (6)
- # cursive (47)
- # datahike (7)
- # datomic (18)
- # defnpodcast (1)
- # fulcro (17)
- # graalvm (8)
- # graphql (4)
- # helix (5)
- # honeysql (5)
- # introduce-yourself (1)
- # jobs (5)
- # jobs-discuss (4)
- # malli (20)
- # meander (4)
- # mental-health (1)
- # off-topic (41)
- # pathom (18)
- # podcasts-discuss (2)
- # re-frame (20)
- # react (1)
- # reagent (22)
- # reitit (2)
- # releases (2)
- # remote-jobs (1)
- # reveal (2)
- # sci (10)
- # shadow-cljs (42)
- # sql (20)
- # tools-deps (7)
- # vim (2)
- # xtdb (51)
I'm having trouble working with the primereact ui library, specifically this (trimmed for space) templating example from https://primefaces.org/primereact/showcase/#/datatable/templating:
export class DataTableTemplatingDemo extends Component {
constructor(props) {
super(props);
this.state = {
products: []
};
this.ratingBodyTemplate = this.ratingBodyTemplate.bind(this);
this.statusBodyTemplate = this.statusBodyTemplate.bind(this);
}
ratingBodyTemplate(rowData) {
return <Rating value={rowData.rating} readOnly cancel={false} />;
}
statusBodyTemplate(rowData) {
return <span className={`product-badge status-${rowData.inventoryStatus.toLowerCase()}`}>{rowData.inventoryStatus}</span>;
}
render() {
return (
<div className="datatable-templating-demo">
<div className="card">
<DataTable value={this.state.products}>
<Column field="name" header="Name"></Column>
<Column field="rating" header="Reviews" body={this.ratingBodyTemplate}></Column>
<Column header="Status" body={this.statusBodyTemplate}></Column>
</DataTable>
</div>
</div>
);
}
}
As you can see, this feature allows you to write custom templates for elements in a data table by defining the functions within the lements, and then referring to them in the 'body' prop of the column you want to use the template. My stab at a roughly equivalent cljs is (again, I'm trimming way down to show the part I'm having trouble with, so I know there are other parts that might not be working here):
(defn junk-button [_] [:> Button {:label "test"}])
(defn table []
(let [del-button (r/as-element junk-button)]
[:> DataTable {:value table-data
:on-row-reorder reorder
:resizableColumns true}
[:> Column {:header "Delete"
:body [del-button]}]]))
When I actually load info into the table, I get an error saying "Uncaught TypeError: this.props.body is not a function".
Any ideas how to define a custom element in cljs here? Many thanks!!In the JSX example, you pass the function. In the CLJS code, you pass a vector - why? Just pass the function.
Apart from that, it still won't work because Column
expects that function to return a React element, but in your case it returns Hiccup. Wrap its result with reagent.core/as-element
.
Thanks for the response. I think I had it in the vector because when I pass it in directly as you suggest, I get a different error: Uncaught Error: Objects are not valid as a React child (found: object with keys {ns, name, fqn, _hash, cljs$lang$protocol_mask$partition0$, cljs$lang$protocol_mask$partition1$}). If you meant to render a collection of children, use an array instead.
no, it happens when I use as-element
. Here is the code that throws the "Objects are not valid as React Child" error: (defn test []
(let [pdfs (-> @comp-state
:pdfs
vals)
table-data (->> @comp-state
:pdfs
vals
(sort-by :order)
(map (fn [m] (dissoc m :file :data-url)))
(map (fn [m] (assoc m :seq (nominal-order (:order m)))))
clj->js)
del-button (r/as-element junk-button)]
[:div {:style {:min-height 350}}
[:> DataTable {:ref (fn [e] (swap! comp-state assoc :dt e))
:value table-data
:on-row-reorder reorder
:resizableColumns true}
[:> Column {:header "Delete"
:body del-button}]]]))
Because you used it wrong. It accepts Hiccup, not a function. https://github.com/reagent-project/reagent/blob/master/doc/InteropWithReact.md#example-function-as-child-components
You have to use as-element
inside junk-button
. The function that you pass to Column
as :body
has to return a React element, and as-element
creates a React element from a Hiccup vector.
as far as I understand it should work similarly to make-reaction
, as the documentation itself suggests
(defonce app-state (r/atom {:people {1 {:name "John Smith"} 2 {:name "Maggie Johnson"}}})) (defn people [] (print :fire 'people " ") (:people @app-state)) (defn person [id] (print :fire 'person " ") (-> @(r/track people) (get id))) (with-out-str (person 1)) ;; => ":fire person :fire people " (with-out-str (person 1)) ;; => ":fire person :fire people " (with-out-str (person 1)) ;; => ":fire person :fire people "
even though the atom hasn't changed, every time it fires all the functions along the way and it doesn't look like anything is cached
I think the issue here is that person
each time returns new instance of defer-able.
(def a (r/atom 10))
(def r1 (ra/reaction (let [n (rand-int @a)] n)))
@r1
;; => 6
@r1
;; => 3
You can't rely on any reactive behavior outside of a reactive context. Views are such a context, when they're rendered by Reagent. Such as other reactions that are themselves used in a reactive context. But REPL is not a reactive context.
I just tested it in a reactive context. Works just fine.
(ns app.core
(:require [reagent.core :as reagent]
[reagent.ratom :as rea]
[reagent.dom]
[clojure.browser.dom]))
(defn view [a b]
(reagent/with-let [x (rea/reaction (+ @a (rand-int 10000)))]
[:div @x ";" @b]))
(defn app []
(reagent/with-let [a (reagent/atom 0)
b (reagent/atom 0)]
[:div
[:button {:on-click #(swap! a inc)} "Inc A"]
[:button {:on-click #(swap! b inc)} "Inc B"]
[view a b]]))
(defn ^:export main []
(reagent.dom/render [app] (clojure.browser.dom/get-element :app)))