Skip to content

Instantly share code, notes, and snippets.

@SneakyPeet
Last active April 4, 2019 03:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SneakyPeet/d872a6cf7def18141fdda249188c18af to your computer and use it in GitHub Desktop.
Save SneakyPeet/d872a6cf7def18141fdda249188c18af to your computer and use it in GitHub Desktop.
Clojurescript Date Selector

A simple clojurescript datepicker using rum, cljs-time and bulma for style

(ns date-select.core
(:require [rum.core :as rum]
[cljs-time.core :as time]))
(defn initial-date
([] (let [selected (time/now)]
{:year (time/year selected)
:month (time/month selected)
:day (time/day selected)}))
([year] (initial-date year 1 1))
([year month] (initial-date year month 1))
([year month day]
(let [selected (time/date-time year month day)]
{:year (time/year selected)
:month (time/month selected)
:day (time/day selected)})))
(rum/defcs DateCapture
"Params
start-year :int
end-year: int
label: string
change: fn taking a map as param. example {:year 2019 :month 2 :day 9}
initial-date: a map of {:year 2019 :month 2 :day 8} | use initial-date fn to construct"
< (rum/local nil ::year) (rum/local nil ::month) (rum/local nil ::day)
{:will-mount (fn [{*day ::day *month ::month *year ::year :as state}]
(let [now (time/now)
year (time/year now)
[start-year end-year _ change init-opts] (:rum/args state)]
(reset! *year (get init-opts :year year))
(reset! *month (get init-opts :month (time/month now)))
(reset! *day (get init-opts :day (time/day now)))
(assoc state
::years (range start-year (inc end-year))
::months (range 1 13)
::notify-change (fn [] (change {:year @*year :month @*month :day @*day})))))
:did-update (fn [{notify-change ::notify-change :as state}]
(notify-change)
state)}
[{*day ::day *month ::month *year ::year :as state} start-year end-year label change]
(let [last-day-of-month (time/day (time/last-day-of-the-month @*year @*month))
days (range 1 (inc last-day-of-month))
on-change (fn [*k]
(fn [e]
(reset! *k (js/parseInt (.. e -target -value)))
(let [new-last-day-of-month (time/day (time/last-day-of-the-month @*year @*month))]
(when (< new-last-day-of-month @*day)
(reset! *day 1)))))
field (fn [range-coll *k]
[:div.field
[:div.control
[:div.select
[:select {:value @*k :on-change (on-change *k)}
(map-indexed (fn [i x] [:option {:key i} x]) range-coll)]]]])]
[:div.field.is-horizontal
[:div.field-label.is-normal
[:label.label label]]
[:div.field-body
(field (::years state) *year)
(field (::months state) *month)
(field days *day)]]))
(ns date-select.example
(:require [date-select.core :as ds]))
(def on-change prn)
(def label "My Date Selector")
(def initial-date (ds/initial-date 2018 1 1))
(ds/DateCapture 2018 2020 label on-change initial-date)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment