Fork me on GitHub

I'm having trouble working with the primereact ui library, specifically this (trimmed for space) templating example from

export class DataTableTemplatingDemo extends Component {

    constructor(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>
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.


That's exactly because you didn't use as-element.


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}]]]))


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.


Bingo! Thanks so much!!!!!!

馃憤 2

I have trouble understanding the r/track ...


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

Karol W贸jcik12:06:22

I think the issue here is that person each time returns new instance of defer-able.


it looks like I don't understand reaction either, and I was almost sure I did


(def a (r/atom 10))

(def r1 (ra/reaction (let [n (rand-int @a)] n)))

;; => 6
;; => 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'm pretty sure that's how I tested it in the past


I just tested it in a reactive context. Works just fine.

(ns app.core
  (:require [reagent.core :as reagent]
            [reagent.ratom :as rea]

(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)]
     [: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)))


So if you press Inc B, the part before ; won't change, as expected.