"] " element of header row)"
49 | ", use " [:code.inline-code "::column-label"] " parameter. It can be one of the following:"]
50 |
51 | [:ul.ui.list
52 | [:li "A string, that will be rendered as is"]
53 | [:li "A Reagent component"]]]
54 |
55 | [components/tabs-wrapper
56 | :basic-definition
57 | [::subs/basic-definition-data]
58 | [{::dt/column-key [:index]}
59 | {::dt/column-key [:name]
60 | ::dt/column-label "Name"}
61 | {::dt/column-key [:stats :play_count]
62 | ::dt/column-label formatters/play-count-th}]
63 | nil
64 | [{:data-tab "th-fourammter-source"
65 | :label "Play Count Formatter Source"
66 | :component (fn []
67 | [formatters/formatted-function-def
68 | (with-out-str (r/source formatters/play-count-th))])}]]])
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/).
3 |
4 | ## [0.6.0] - 2017-09-09
5 | ### Breaking
6 | - Moved default-pagination-controls view component to new namespace: re-frame-datatable.views
7 | - Reorganized documentation in a new way (including subsections)
8 |
9 | ### Changed
10 | - Update to ClojureScript 1.9.908, re-frame 0.10.1 and reagent 0.7.0
11 |
12 | ### Added
13 | - Ability to change pagination size via events (+ default page size selector control)
14 | - Support for custom sorting comparator function via ::comp-fn
15 |
16 | ### Fixed
17 | - Fixed bug with incorrect ::cure-page calculation when data-source has changed and this page is not exist
18 | - Fixed propagation of options via :component-did-update
19 |
20 |
21 | ## [0.5.2] - 2017-05-26
22 | ### Added
23 | - Sorting to work with nested data paths (Thanks to @ChrisHacker)
24 | - Sorting on values other than the column-key value (Thanks to @ChrisHacker)
25 | - Support ints in ::column-key (allows datatable to work with elements in collection that have nested vectors)
26 |
27 | ### Fixed
28 | - Update ClojureScript 1.9.542 and fix spec ns
29 |
30 |
31 | ## [0.5.1] - 2017-01-17
32 | ### Added
33 | - ::column-label became optional
34 | - ::column-label can now accept either string as before or an arbitrary Reagent component
35 | - New option: ::header-enabled? which can be used to prevent DataTable from rendering
36 | - "sortable" columns are marked with special class for styling via CSS
37 |
38 | ## [0.5.0] - 2016-12-30
39 | ### Breaking
40 | - Pagination controls are not rendered by default, extracted into separate component
41 |
42 | ### Added
43 | - Ability to create own pagination controls
44 | - Callback to unselect all rows in DataTable
45 | - Customizable rendering of empty DataTable
46 |
47 | ### Fixed
48 | - Empty DataTable doesn't select "selected all" checkbox
49 | - Default pagination control works correctly with empty DataTable
50 |
51 | ## [0.4.0] - 2016-12-27
52 | ### Added
53 | - Support for optional extra row inside `` via `::extra-header-row-component`
54 | - Support for optional `
` via `::footer-component`
55 | - Ability to inject arbitrary classes into rendered `
` and `
` elements
56 | - Bumped [re-frame](https://github.com/Day8/re-frame) version to 0.9.1
57 |
58 | ## [0.3.0] - 2016-12-21
59 | ### Added
60 | - Selection of rows (including a subscription to selected elements)
61 |
62 | ### Changed
63 | - Changed all datatable-related keywords to namespace-qualified keywords
64 |
65 | ## [0.2.0] - 2016-12-19
66 | ### Added
67 | - Switched to [re-frame](https://github.com/Day8/re-frame) 0.9.0
68 | - `::render-fn` key that allows to specify custom rendering function
69 | - Styling of `
` element after sorting
70 |
71 | ### Removed
72 | - `::th-classes` key from `columns-def` vector elements. Styling should happen outside of component
73 |
74 | ## 0.1.0 - 2016-12-15
75 | ### Added
76 | - Initial DataTable implmenetation
77 | - sorting
78 | - pagination
79 | - Styling of `
` element
80 |
--------------------------------------------------------------------------------
/src/re_frame_datatable/views.cljs:
--------------------------------------------------------------------------------
1 | (ns re-frame-datatable.views
2 | (:require [re-frame.core :as re-frame]
3 | [re-frame-datatable.core :as dt]))
4 |
5 |
6 |
7 | (defn default-pagination-controls [db-id data-sub]
8 | (let [pagination-state (re-frame/subscribe [::dt/pagination-state db-id data-sub])]
9 | (fn []
10 | (let [{:keys [::dt/cur-page ::dt/pages]} @pagination-state
11 | total-pages (if (pos? (count pages)) (count pages) 1)]
12 | [:div.re-frame-datatable.page-selector
13 | {:style {:display "inline-block"}}
14 | (let [prev-enabled? (pos? cur-page)]
15 | [:span
16 | {:on-click
17 | #(when prev-enabled?
18 | (re-frame/dispatch
19 | [::dt/select-prev-page
20 | db-id @pagination-state]))
21 | :style {:cursor (when prev-enabled? "pointer")
22 | :color (when-not prev-enabled? "rgba(40,40,40,.3)")}}
23 | (str \u25C4 " PREVIOUS ")])
24 |
25 | [:select
26 | {:value cur-page
27 | :on-change #(re-frame/dispatch
28 | [::dt/select-page
29 | db-id @pagination-state
30 | (js/parseInt (-> % .-target .-value))])}
31 | (doall
32 | (for [page-index (range total-pages)]
33 | ^{:key page-index}
34 | [:option
35 | {:value page-index}
36 | (str "Page " (inc page-index) " of " total-pages)]))]
37 |
38 | (let [next-enabled? (< cur-page (dec total-pages))]
39 | [:span
40 | {:style {:cursor (when next-enabled? "pointer")
41 | :color (when-not next-enabled? "rgba(40,40,40,.3)")}
42 | :on-click #(when next-enabled?
43 | (re-frame/dispatch
44 | [::dt/select-next-page
45 | db-id @pagination-state]))}
46 | (str " NEXT " \u25BA)])]))))
47 |
48 |
49 |
50 | (defn per-page-selector [db-id data-sub]
51 | (let [pagination-state (re-frame/subscribe [::dt/pagination-state db-id data-sub])
52 | per-page-values [5 10 25 50 100]]
53 |
54 | (fn []
55 | (let [{:keys [::dt/per-page]} @pagination-state]
56 | [:div.re-frame-datatable.per-page-selector
57 | {:style {:display "inline-block"}}
58 | [:span "Page Size: "]
59 | [:select
60 | {:value (or per-page dt/default-per-page)
61 | :on-change #(re-frame/dispatch
62 | [::dt/set-per-page-value
63 | db-id @pagination-state
64 | (js/parseInt (-> % .-target .-value))])}
65 | (doall
66 | (for [per-page-option (->> per-page-values
67 | (cons per-page)
68 | (filter (complement nil?))
69 | (set)
70 | (sort))]
71 | ^{:key per-page-option}
72 | [:option
73 | {:value per-page-option}
74 | per-page-option]))]]))))
75 |
--------------------------------------------------------------------------------
/docs/src/cljs/re_frame_datatable_docs/sections/cell_rendering.cljs:
--------------------------------------------------------------------------------
1 | (ns re-frame-datatable-docs.sections.cell-rendering
2 | (:require [re-frame-datatable-docs.components :as components]
3 | [re-frame-datatable-docs.formatters :as formatters]
4 | [re-frame-datatable-docs.table-views :as table-views]
5 | [cljs.repl :as r]
6 |
7 | [re-frame-datatable-docs.subs :as subs]
8 | [re-frame-datatable.core :as dt]
9 | [re-frame-datatable.views :as dt-views]))
10 |
11 |
12 |
13 | (defn cell-rendering []
14 | [:div
15 | [:div
16 | "Each entry in " [:code.inline-code "columns-def"] " vector supports " [:code.inline-code "::render-fn"]
17 | " option that allows to specify function that defines Reagent component which should be used for rendering. This function should have the following signature: "
18 | [:pre
19 | [:code {:class "clojure"}
20 | "(defn custom-formatter [value & [item]])"]]
21 | [:ul
22 | [:li [:code.inline-code "value"] " - actual value of column property in this row"]
23 | [:li [:code.inline-code "item"] " - actual object in this row (can be used to pass arbitrary key-value pairs to cell rendering function)"]]]
24 |
25 | [:h5.ui.header "Basic custom rendering"]
26 | [components/tabs-wrapper
27 | :cell-rendering-basic
28 | [::subs/cell-rendering-data]
29 | [{::dt/column-key [:name]
30 | ::dt/column-label "Name"}
31 | {::dt/column-key [:artist]
32 | ::dt/column-label "Artist"
33 | ::dt/render-fn formatters/artist-formatter}
34 | {::dt/column-key [:duration]
35 | ::dt/column-label "Duration"
36 | ::dt/render-fn formatters/duration-formatter}
37 | {::dt/column-key [:album]
38 | ::dt/column-label "Album"
39 | ::dt/render-fn formatters/album-formatter}
40 | {::dt/column-key [:stats :rating]
41 | ::dt/column-label "Rating"
42 | ::dt/render-fn formatters/rating-formatter}]
43 | {::dt/table-classes ["ui" "very" "basic" "collapsing" "celled" "table"]}
44 | [{:data-tab "formatters-source"
45 | :label "Formatters Source"
46 | :component (fn []
47 | [formatters/formatted-function-def
48 | (with-out-str (r/source formatters/artist-formatter))
49 | (with-out-str (r/source formatters/duration-formatter))
50 | (with-out-str (r/source formatters/album-formatter))
51 | (with-out-str (r/source formatters/rating-formatter))])}]]])
52 |
53 |
54 |
55 | (defn using-item-argument []
56 | [:div
57 | [components/tabs-wrapper
58 | :cell-rendering-advanced
59 | [::subs/cell-rendering-data]
60 | [{::dt/column-key [:name]
61 | ::dt/column-label "Song"
62 | ::dt/render-fn formatters/song-digest-formatter}
63 | {::dt/column-key [:artist]
64 | ::dt/column-label "Artist"
65 | ::dt/render-fn formatters/artist-formatter}]
66 | {::dt/table-classes ["ui" "very" "basic" "collapsing" "celled" "table"]}
67 | [{:data-tab "formatters-source"
68 | :label "Formatters Source"
69 | :component (fn []
70 | [formatters/formatted-function-def
71 | (with-out-str (r/source formatters/song-digest-formatter))
72 | (with-out-str (r/source formatters/artist-formatter))])}]]])
73 |
--------------------------------------------------------------------------------
/re-frame-datatable.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # re-frame-datatable
2 |
3 | A UI component for [re-frame](https://github.com/Day8/re-frame).
4 | Uses existing subscription to data source in re-frame's `app-db` and declarative definition of how to render it as a table.
5 | Supports sorting, pagination and some basic CSS manipulations for generated table.
6 |
7 | ## Quick links
8 |
9 | * [Documentation Website](https://kishanov.github.io/re-frame-datatable/) - re-frame app that shows how to use differt DataTable options
10 | * [Complete example app](https://kishanov.github.io/re-frame-datatable-example/) - GMail-like interface which uses most of the features of DataTable component
11 |
12 |
13 | ## Usage
14 |
15 | Leiningen
16 |
17 | [](http://clojars.org/re-frame-datatable)
18 |
19 | In your application add the following dependency to the file that defines views in your re-frame application:
20 |
21 | ```clojure
22 | (ns re-frame-datatable-docs.views
23 | (:require [re-frame-datatable.core :as dt]
24 | [your.app.subs :as subs] ; Namespace in which re-frame subscriptions are defined
25 | ;...))
26 | ```
27 |
28 | Here is a sample [Reagent](https://github.com/reagent-project/reagent) component which defines datatable (assuming that `subs` namespace constains `::songs-list` subscription which returns data in the following format: `[{:index 1 :name "Mister Sandman" :duration 136} ...]`)
29 |
30 |
31 | ```clojure
32 | (defn sneak-peek-for-readme []
33 | [dt/datatable
34 | :songs
35 | [::subs/songs-list]
36 | [{::dt/column-key [:index]
37 | ::dt/sorting {::dt/enabled? true}
38 | ::dt/column-label "#"}
39 | {::dt/column-key [:name]
40 | ::dt/column-label "Name"}
41 | {::dt/column-key [:duration]
42 | ::dt/column-label "Duration"
43 | ::dt/sorting {::dt/enabled? true}
44 | ::dt/render-fn (fn [val]
45 | [:span
46 | (let [m (quot val 60)
47 | s (mod val 60)]
48 | (if (zero? m)
49 | s
50 | (str m ":" (when (< s 10) 0) s)))])}]
51 | {::dt/pagination {::dt/enabled? true
52 | ::dt/per-page 5}
53 | ::dt/table-classes ["ui" "table" "celled"]}])
54 | ```
55 |
56 | `dt/datatable` component accepts the following arguments:
57 |
58 | * `datatable-key` - a keyword, that will be used in re-frame's `app-db` to store datatable state
59 | * `subscription-vec` - a vector, which will be used by datatable to render data via `(re-frame/subscribe subscription-vec)`
60 | * `columns-def` - a vector of maps, that defines how each column of datatable should look like
61 | * `options` - optional map of additional options
62 |
63 | For the complete documenation and live examples visit [Documentation website](https://kishanov.github.io/re-frame-datatable/).
64 |
65 | ## How it works
66 |
67 | `re-frame-datatable` expects a re-frame subscription, that returns a collection of maps. It will render an HTML table (using `
element of sorted column will have 2 HTML classes assigned: "
27 | [:code.inline-code "sorted-by"] " and either " [:code.inline-code "asc"] " or " [:code.inline-code "desc"]
28 | ". This allows to apply CSS styling to this column to emphasize that the table was sorted by it. DataTable doesn't render additional visual clues to show emphasize it."]]
29 |
30 |
31 | [components/tabs-wrapper
32 | :sorting
33 | [::subs/basic-definition-data]
34 | [{::dt/column-key [:index]
35 | ::dt/column-label "#"
36 | ::dt/sorting {::dt/enabled? true}}
37 | {::dt/column-key [:name]
38 | ::dt/column-label "Name"}
39 | {::dt/column-key [:stats :play_count]
40 | ::dt/column-label "Play count"
41 | ::dt/sorting {::dt/enabled? true}}]
42 | {::dt/table-classes ["ui" "table"]}
43 | [{:data-tab "css-example"
44 | :label "CSS"
45 | :component (fn []
46 | [:pre
47 | [:code {:class "css"}
48 | "
49 | table.re-frame-datatable > thead th.sorted-by:after {
50 | display: inline-block;
51 | }
52 |
53 | table.re-frame-datatable > thead th.sorted-by.desc:after {
54 | content: '\f0d7';
55 | }
56 |
57 | table.re-frame-datatable > thead th.asc:after {
58 | content: '\f0d8';
59 | }
60 |
61 | table.re-frame-datatable > thead th:after {
62 | display: none;
63 | font-family: Icons;
64 | margin-left: .5em;
65 | }"]])}]]])
66 |
67 |
68 |
69 | (defn custom-sorting-fn []
70 | [:div
71 | [:div
72 | "To define custom comparator for sorting function, provide "
73 | [:code.inline-code "::comp-fn"] " with the function that accepts a function that will be used internally as a third argument to "
74 | [:a {:href "https://clojuredocs.org/clojure.core/sort-by"} "sort-by"] " (DataTable uses it internally in to sort table data). "
75 | "Note that DataTable requires a function, so things like keywords should be wrapped into function with proper signature."]
76 |
77 | [components/tabs-wrapper
78 | :sorting
79 | [::subs/basic-definition-data]
80 | [{::dt/column-key [:index]
81 | ::dt/column-label "#"}
82 | {::dt/column-key [:name]
83 | ::dt/column-label "Name"}
84 | {::dt/column-key [:stats]
85 | ::dt/column-label "Play count"
86 | ::dt/sorting {::dt/enabled? true
87 | ::dt/comp-fn formatters/sort-play-count-comp}}]
88 | {::dt/table-classes ["ui" "table"]}
89 | [{:data-tab "comparator-fn-source"
90 | :label "Comparator Fn Source"
91 | :component (fn []
92 | [formatters/formatted-function-def
93 | (with-out-str (r/source formatters/sort-play-count-comp))])}]]])
94 |
--------------------------------------------------------------------------------
/docs/src/cljs/re_frame_datatable_docs/sections/rows_selection.cljs:
--------------------------------------------------------------------------------
1 | (ns re-frame-datatable-docs.sections.rows-selection
2 | (:require [re-frame-datatable-docs.components :as components]
3 | [re-frame-datatable-docs.formatters :as formatters]
4 | [re-frame-datatable-docs.table-views :as table-views]
5 | [cljs.repl :as r]
6 |
7 | [re-frame-datatable-docs.subs :as subs]
8 | [re-frame-datatable.core :as dt]
9 | [re-frame-datatable.views :as dt-views]
10 | [re-frame.core :as re-frame]))
11 |
12 |
13 | (defn enable-rows-selection []
14 | [:div
15 | [:div
16 | [:p
17 | "To enable selection, pass " [:code.inline-code "::selection"] " option with value " [:code.inline-code "{::enabled? true}"] "."]
18 |
19 | [:div
20 | "To access selected items, DataTable provides subsciprtion " [:code.inline-code "::selected-items"] ", which accepts 2 arguments"
21 | [:ul
22 | [:li [:code.inline-code "datatable-id"] " - same keyword, that was used in DataTable definition"]
23 | [:li [:code.inline-code "data-sub"] " - same subscription vector, that was used in DataTable definition"]]]]
24 |
25 | [components/tabs-wrapper
26 | :rows-selection-basic
27 | [::subs/basic-definition-data]
28 | [{::dt/column-key [:name]
29 | ::dt/column-label "Name"}
30 | {::dt/column-key [:stats :play_count]
31 | ::dt/column-label "Play count"}]
32 | {::dt/table-classes ["ui" "very" "basic" "collapsing" "celled" "table"]
33 | ::dt/selection {::dt/enabled? true}}
34 | [{:data-tab "selected-items-preview"
35 | :label "Selected Items Source"
36 | :component (fn []
37 | [:pre
38 | [:code {:class "clojure"}
39 | (with-out-str (r/source table-views/selected-rows-preview))]])}]
40 | (fn [dt-def]
41 | [:div.ui.two.column.divided.grid
42 | [:div.column
43 | [:h5.ui.header "Table"]
44 | dt-def]
45 |
46 | [:div.column
47 | [:h5.ui.header "Selected items"]
48 | [formatters/formatted-code
49 | @(re-frame/subscribe [::dt/selected-items :rows-selection-basic [::subs/basic-definition-data]])]]])]])
50 |
51 |
52 |
53 | (defn selection-and-other-options []
54 | [:div
55 | [:div
56 | [:p
57 | "Row selection also works with pagination and sorting. If pagination is enabled, \"select/unselect all\" will select/unselect all elements on all pages"]
58 |
59 | [components/warning-message
60 | [:div
61 | [:p
62 | "If you plan to modify the content of DataTable based on selection (for example, select n elements and delete them via separate handler),
63 | you also need to dispatch an vent that will unselect all items in DataTable.
64 | If you'll not do that, after deteletion some other elements will remain selected based on internal DataTable indexing mechanism."]
65 | [:p
66 | "To unselect all selected rows, dispatch the following event from the handler which modifies the content of DataTable."]
67 | [:pre
68 | [:code {:class "clojure"}
69 | "[::dt/unselect-all-rows datatable-id]"]]]]]
70 |
71 | [components/tabs-wrapper
72 | :rows-selection-pagination-sorting
73 | [::subs/pagination-data]
74 | [{::dt/column-key [:index]
75 | ::dt/column-label "#"
76 | ::dt/sorting {::dt/enabled? true}}
77 | {::dt/column-key [:name]
78 | ::dt/column-label "Name"
79 | ::dt/sorting {::dt/enabled? true}}
80 | {::dt/column-key [:stats :play_count]
81 | ::dt/column-label "Play count"
82 | ::dt/sorting {::dt/enabled? true}}]
83 | {::dt/table-classes ["ui" "very" "basic" "collapsing" "celled" "table"]
84 | ::dt/selection {::dt/enabled? true}
85 | ::dt/pagination {::dt/enabled? true
86 | ::dt/per-page 5}}
87 | nil
88 | (fn [dt-def]
89 | [:div.ui.two.column.divided.grid
90 | [:div.column
91 | [:h5.ui.header "Table"]
92 | [dt-views/default-pagination-controls :rows-selection-pagination-sorting [::subs/pagination-data]]
93 | dt-def]
94 |
95 | [:div.column
96 | [:h5.ui.header "Selected items"]
97 | [formatters/formatted-code
98 | @(re-frame/subscribe [::dt/selected-items :rows-selection-pagination-sorting [::subs/pagination-data]])]]])]])
99 |
--------------------------------------------------------------------------------
/docs/src/cljs/re_frame_datatable_docs/sections/styling.cljs:
--------------------------------------------------------------------------------
1 | (ns re-frame-datatable-docs.sections.styling
2 | (:require [re-frame-datatable-docs.components :as components]
3 | [re-frame-datatable-docs.formatters :as formatters]
4 | [re-frame-datatable-docs.table-views :as table-views]
5 |
6 | [re-frame-datatable-docs.subs :as subs]
7 | [re-frame-datatable.core :as dt]
8 |
9 | [cljs.repl :as r]
10 | [re-frame-datatable.views :as dt-views]))
11 |
12 |
13 | (defn css-options []
14 | [:div
15 | [:div
16 | "HTML table that will be generated will have a standard structure:"
17 | [:pre
18 | [:code {:class "html"}
19 | "
20 |
21 |
...
22 |
23 |
24 |
...
25 | ...
26 |
27 |
28 | "]]
29 |
30 | "To avoid drilling too many \"holes\" in datatable most of the styling should be done in CSS via CSS selectors based on this structure.
31 | To enable that, datatable allows to provide a vector of CSS classes that should be applied to "
32 | [:code.inline-code "
"] " HTML tag, and the rest can be done via CSS selectors."]
33 | [:div "To provide CSS classes that should be applied to
"] " element. "
62 | "DataTable can set these classes via column definition by providing " [:code.inline-code "::td-class-fn"] " option that accepts a function with following signature:"]
63 | [:pre
64 | [:code {:class "clojure"}
65 | "(defn td-class-fn [cell-value row-value]
66 | {:post [(seq? %)
67 | (every? (fn [t] (or (string? t) (nil? t))) %)]}
68 | ;...
69 | )"]]
70 |
71 | [:p
72 | "i.e. function should return a sequence of CSS classes (represented as strings) that should be applied to " [:code.inline-code "
"] " element."]
73 |
74 | [components/info-message
75 | [:div "In the example below " [:code.inline-code "row-value"] " argument is not provided to neither of functions, because the value of class can be determined by single property only."]]]
76 |
77 | [components/tabs-wrapper
78 | :marking-cells
79 | [::subs/marking-elements-data]
80 | [{::dt/column-key [:index]
81 | ::dt/column-label "#"}
82 | {::dt/column-key [:name]
83 | ::dt/column-label "Name"}
84 | {::dt/column-key [:stats :play_count]
85 | ::dt/column-label "Play Count"
86 | ::dt/td-class-fn table-views/play-count-td-classes}
87 | {::dt/column-key [:stats :rating]
88 | ::dt/column-label "Rating"
89 | ::dt/td-class-fn table-views/rating-td-classes}]
90 | {::dt/table-classes ["ui" "celled" "table"]}
91 | [{:data-tab "css-classes-source"
92 | :label "CSS Classes Source"
93 | :component (fn []
94 | [formatters/formatted-function-def
95 | (with-out-str (r/source table-views/play-count-td-classes))
96 | (with-out-str (r/source table-views/rating-td-classes))])}]]])
97 |
98 |
99 |
100 | (defn styling-rows []
101 | [:div
102 | [:div
103 | [:p
104 | "Similar capabilities are available for the complete row, with the difference that the option is defined via " [:code.inline-code "options"] " argument."
105 | [:code.inline-code "::tr-class-fn"] " option that accepts a function with following signature:"]
106 | [:pre
107 | [:code {:class "clojure"}
108 | "(defn td-class-fn [row-value]
109 | {:post [(seq? %)
110 | (every? (fn [t] (or (string? t) (nil? t))))]}
111 | ;...
112 | )"]]]
113 |
114 | [components/tabs-wrapper
115 | :marking-rows
116 | [::subs/marking-elements-data]
117 | [{::dt/column-key [:index]
118 | ::dt/column-label "#"}
119 | {::dt/column-key [:name]
120 | ::dt/column-label "Name"}
121 | {::dt/column-key [:stats :play_count]
122 | ::dt/column-label "Play Count"}
123 | {::dt/column-key [:stats :rating]
124 | ::dt/column-label "Rating"}]
125 | {::dt/table-classes ["ui" "celled" "table"]
126 | ::dt/tr-class-fn table-views/play-count-tr-classes}
127 | [{:data-tab "css-classes-source"
128 | :label "CSS Classes Source"
129 | :component (fn []
130 | [formatters/formatted-function-def
131 | (with-out-str (r/source table-views/play-count-tr-classes))])}]]])
132 |
--------------------------------------------------------------------------------
/docs/src/cljs/re_frame_datatable_docs/table_views.cljs:
--------------------------------------------------------------------------------
1 | (ns re-frame-datatable-docs.table-views
2 | (:require [re-frame.core :as re-frame]
3 | [re-frame-datatable.core]
4 | [re-frame-datatable-docs.subs]))
5 |
6 |
7 |
8 | (defn aggregation-row []
9 | [:tr
10 | [:th {:col-span 1} ""]
11 | [:th {:col-span 3} "Album info"]])
12 |
13 |
14 |
15 | (defn total-play-count-footer []
16 | ; ::total-play-count subscription returns sum of all :play_count values
17 | ; for ::basic-definition-data subscription
18 | (let [total-count (re-frame/subscribe [::re-frame-datatable-docs.subs/total-play-count])]
19 | [:tr
20 | [:th {:col-span 2}]
21 | [:th
22 | [:strong (str @total-count " total")]]]))
23 |
24 |
25 |
26 | (defn play-count-td-classes [play-count]
27 | "Set 'disabled' class for the song if it hasn't been played yet"
28 | [(when (zero? play-count)
29 | "disabled")])
30 |
31 |
32 |
33 | (defn rating-td-classes [rating]
34 | "Color-code cell by rating"
35 | [(cond
36 | (= 5 rating) "positive"
37 | (#{3 4} rating) "warning"
38 | (nil? rating) nil ; DataTable will ignore all nil values in classes vector
39 | :else "negative")])
40 |
41 |
42 |
43 | (defn play-count-tr-classes
44 | "For all songs that hasn't been played yet, define