-
Notifications
You must be signed in to change notification settings - Fork 84
Multi Select: aka tags
Conor White-Sullivan edited this page Apr 30, 2017
·
1 revision
You want a multi-select component with just reagent
use something like this
(let [selections (r/atom [])]
[multi {:typeahead-atom (r/atom "")
:on-delete #(reset! selections (vec (filter (partial not= %)) @selections)))
:attr {:auto-focus true}
:selections-visible true
:selections-atom selections
:suggestions ["Apple" "Bannanas""Grapes""Algebra"]
:save! #(swap! selections conj %)}])
defined like this
(defn component [{:keys [highlight-class
placeholder
item-class
list-class
highlight-style
container-class
suggestions
filter-fn
save!
attr
item-style
on-remove!
selections-atom
selection-class
on-delete
use-styles
input-style
]
:or {attr {}
container-class "tags"
list-class ""
input-style {:outline "1px solid transparent"}
highlight-style {:background-color "gray"}
item-style {}
;; highlight-class "highlight"
on-remove #(swap! selections-atom (fn [y] (remove #{%} y)))
selection-class "tags-output-item"
filter-fn (fn [typeahead-atom x]
(-> (.toLowerCase x)
(.indexOf (.toLowerCase @typeahead-atom))
(> -1)))}}]
(let [typeahead-atom (r/atom "")
selected-index (r/atom -1)
typeahead-hidden? (r/atom false)
mouse-on-list? (r/atom false)
reset-internals! #(do
(reset! selected-index 0)
(reset! typeahead-atom ""))]
(fn []
(let [options (if (clojure.string/blank? @typeahead-atom)
[]
(filter (partial filter-fn typeahead-atom) (deref-or-value suggestions)))
matching-options (filter (comp not (set @selections-atom)) options)
choose-selected #(if (and (not-empty matching-options)
(> @selected-index -1))
(let [choice (nth matching-options @selected-index)]
(save! choice)
(reset-internals!))
(when (and (not (str/blank? @typeahead-atom))
;; might be nice to return typeahead-atom warning to user
;; idea is not to allow duplicate items
(not ((set @selections-atom) @typeahead-atom)))
(do
(save! @typeahead-atom)
(reset-internals!))))]
[:div
{:class (if use-styles "tags flex"
)}
[:div.tags-output
(when @selections-atom
(for [x @selections-atom]
^{:key x}
[:span
{:class selection-class
:on-click #(on-remove! x)}
(str x)]
))
[:input
(merge attr {:value @typeahead-atom
:placeholder placeholder
:on-change #(reset! typeahead-atom (-> % .-target .-value))
:style input-style
:on-key-down #(do
(case (.-which %)
38 (do
(.preventDefault %)
(when-not (= @selected-index -1)
(swap! selected-index dec)))
40 (do
(.preventDefault %)
(when-not (= @selected-index (dec (count matching-options)))
(swap! selected-index inc)))
9 (choose-selected)
13 (choose-selected)
8 (when (clojure.string/blank? @typeahead-atom)
(on-delete))
27 (do #_(reset! typeahead-hidden? true)
(reset! selected-index -1))
"default"))})]
[:ul {:style
{:display (if (or (empty? matching-options) @typeahead-hidden?) :none :block) }
:class list-class
:on-mouse-enter #(reset! mouse-on-list? true)
:on-mouse-leave #(reset! selected-index -1)}
(doall
(map-indexed
(fn [index result]
[:li {:tab-index index
:key index
:style (if (= @selected-index index) highlight-style item-style)
:class (if (= @selected-index index) highlight-class item-class)
:on-mouse-over #(do
(reset! selected-index (js/parseInt (.getAttribute (.-target %) "tabIndex"))))
:on-click #(do
(reset! typeahead-atom "")
(save! result)
)}
result])
matching-options))]]])
)))
Or just read the re-com source code, strip it apart and figure out what you like -- that's how I arrived at the component above